Python類とタプルの深さ掘削II【経験】
3975 ワード
前のページでは、クラスのオブジェクトを呼び出してインスタンスオブジェクトを生成する過程で発生する可能性のある名前空間に関する問題を解決しました。今回は、クラスのオブジェクト自体がどのように発生したかを振り返ってみます。
私たちはtype()の方法を知っていますが、オブジェクトの種類を確認したり、このオブジェクトがどのタイプから生まれたかを判断したりできます。
クラス定義の文法は実際にtype(name、bases、dict)に変換されます。ここでnameパラメータはクラスの名前です。basesは親クラスの元グループを継承し、dictはクラスの属性と方法です。
例を生成するときは、__u u u_u uを呼び出します。init_方法は初期化されていますが、実際にはその前に__u u u_u uを呼び出します。new_方法は実例を作成し、_u u u u u u uを経由します。init_初期化は、__u u u_u uみたいです。new_変数の宣言を担当します。init_宣言の変数を初期化するのと同じです。ここにルールがあります。new_cls)の戻り値は、clsパラメータの例でなければなりません。init_これはトリガされません。例えば、enum.Enumの定義では、エニュメレーションタイプは単一の例モードであるため、定義されています。new_の場合は、その例に戻っていないと初期化されません。
新しい辞書類を定義し、新しいdict[k]=vを賦与する時
xi検査kは重複していますか?
私たちはtype()の方法を知っていますが、オブジェクトの種類を確認したり、このオブジェクトがどのタイプから生まれたかを判断したりできます。
print(type(12))
print(type('python'))
class A:
pass
print(type(A))
このコードから、クラスのオブジェクトAはtype()によって生成され、つまりtypeは新しいオブジェクトを生成するためにも使用され、またクラスのオブジェクトが生成されることが分かります。したがって、すべての種類のオブジェクトのクラスです。
print(type.__doc__)
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
クラス定義の文法は実際にtype(name、bases、dict)に変換されます。ここでnameパラメータはクラスの名前です。basesは親クラスの元グループを継承し、dictはクラスの属性と方法です。
class A:
pass
#
B = type('A', (), {})
print(A.__name__ == B.__name__)
True
理論的には、これは元の意味ですが、実際の角度からは明らかにクラスの文法を使うほうが便利で合理的です。そして、元の意味はtype類を継承することによって新しいクラスを構築し、特定の動作を行い、特定の行動を持つ種類のオブジェクトを生成します。このように見ると、その本質は普通のクラスのオブジェクトとは違っていません。例を生成するときは、__u u u_u uを呼び出します。init_方法は初期化されていますが、実際にはその前に__u u u_u uを呼び出します。new_方法は実例を作成し、_u u u u u u uを経由します。init_初期化は、__u u u_u uみたいです。new_変数の宣言を担当します。init_宣言の変数を初期化するのと同じです。ここにルールがあります。new_cls)の戻り値は、clsパラメータの例でなければなりません。init_これはトリガされません。例えば、enum.Enumの定義では、エニュメレーションタイプは単一の例モードであるため、定義されています。new_の場合は、その例に戻っていないと初期化されません。
class Enum:
def __new__(cls, value):
print(cls, value)
return value
def __init__(self):
print("Will not be called!")
e = Enum(1)
<class '__main__.Enum'> 1
通常は自分で定義します。new_親類の__u_u uを呼び出す必要があります。new_メソッドは、同じクラスを定義するときに、上記のタイプを呼び出すための使用例であるclsの例を作成します。
class MetaEnum(type):
def __new__(metaclass, name, base, attrs):
print("Metaclass: {}
Name: {}
Parents: {}
Attributes: {}".format(metaclass, name, base, attrs))
return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
# Python 2.7 __metaclass__
# [PEP 3115](https://www.python.org/dev/peps/pep-3115/)
# Python 3.0 class Cls(metaclass=Meta)
test = 0
Metaclass:
Name: Enum
Parents: ()
Attributes: {'__qualname__': 'Enum', '__module__': '__main__', 'test': 0}
Enum , type MetaEnum:
type(Enum)
__main__.MetaEnum
_を除くnew_方法に加えて、PEP 3115は_u u uを定義している。prepare_う属性は、初期化された名前空間(すなわちtypeの3番目のパラメータ)を設定するために使用されますか?それともenum.Enumを例にとって、エニュメレート・タイプの属性名は重複して使用してはいけないことを制限する必要があります。新しい辞書類を定義し、新しいdict[k]=vを賦与する時
xi検査kは重複していますか?
class _EnumDict(dict):
def __init__(self):
super().__init__()
self.members = []
def __setitem__(self, k, v):
if k in self.members:
raise TypeError("Attempted to reuse key: '{}'".format(k))
else:
self.members.append(k)
super().__setitem__(k, v)
class MetaEnum(type):
@classmethod
def __prepare__(metaclass, cls, bases):
return _EnumDict()
def __new__(metaclass, name, base, attrs):
return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
pass
class Color(Enum):
try:
red = 1
red = 2
except TypeError:# as err: ?
print("TypeError catched")
TypeError catched
Pythonではすべて対象としており、すべての対象はいずれかの種類の実例であり、またはある種類のインスタンスであり、typeは自分の元のタイプであり、自分の実例でもあります。