obj.class
在 Python 中, 每一个对象均由某个类进行实例化而创建, 而对象的 __class__ 属性指向了这个类
>>> age = 35
>>> age.__class__
int
>>> name = 'Python'
>>> name.__class__
str
访问 obj.__class__ 等价于调用了 type(obj) 函数
>>> type(age)
int
>>> type(name)
str
元类
对于 Python 语言, 一切皆对象, 类也是对象, 而类是由元类(metaclass)实例化而来
>>> int.__class__
type
>>> age.__class__.__class__
type
通常在 class 语句中不会指定元类, 这样 Python 就会使用默认的元类 type 去实例化一个类
class Test(str):
name = 'Hoss'
# 等价于
class Test(str, metaclass=type):
name = 'Hoss'
也可以动态地使用元类 type, 去实例化一个类对象
Test = type('Test', (str,), {'name': 'Hoss'})
与实例化普通的对象不同, 这里的初始化参数是严格限定的:
x = type(name, bases, dict)
name 为类名, bases 为基类列表, dict 为类属性的字典, 返回值 x 指向新创建的类
在下文中自定义元类的 __new__ 和 __init__ 方法的参数也是一样
自定义元类
我们可以继承 type 自定义一个元类, 然后使用该元类来创建类
class Meta(type):
# 该方法是类方法, 第一个参数是 cls
def __new__(cls, name, bases, dict):
print("invoke __new__, cls:", cls)
# 添加属性 nickname
dict.update(nickname='Hoss')
return super().__new__(cls, name, bases, di
ct)
# 通过 metaclass 指定元类
class TestClass(metaclass=Meta):
pass
print(TestClass.nickname)
以上代码块的执行流程为:
-
遇到第一个 class 语句, 相当于执行
Meta = type('Meta', (type,), {'__new__': xxx})
, 结果是创建了一个元类 Meta -
遇到第二个 class 语句, 相当于执行
TestClass = Meta('TestClass', (), {})
, 在内部继续调用 Meta.___new__(‘TestClass’, (), {}), 在 __new__ 中我们往 dict 参数添加了属性 ‘nickname’, 所以创建的 TestClass 就有了 ‘nickname’ 属性
打印结果:
invoke __new__, cls: <class '__main__.Meta'>
nickname: Hoss
除了 __new__ 方法, 我们还可以在 Meta 中增加 __init__ 方法
class Meta(type):
def __new__(cls, name, bases, dict):
print("invoke __new__, cls:", cls)
return super().__new__(cls, name, bases, dict)
def __init__(self, name, bases, dict):
print("invoke __init__, self:", self)
self.nickname = 'Hoss'
class TestClass(metaclass=Meta):
pass
print("nickname:", TestClass.nickname)
在调用 Meta.__new__(‘TestClass’, (), {}) 后, TestClass 类已被创建, 然后传入 Meta.__init__ 的 self 参数, 继续调用 Meta.__init__(‘TestClass’, (), {})
打印结果:
invoke __new__, cls: <class '__main__.Meta'>
invoke __init__, self: <class '__main__.TestClass'>
nickname: Hoss
还可以增加 __call__ 方法, 干预实例化的过程
class Meta(type):
def __new__(cls, name, bases, dict):
print("invoke __new__, cls:", cls)
return super().__new__(cls, name, bases, dict)
def __init__(self, name, bases, dict):
print("invoke __init__, self:", self)
def __call__(self, x):
print('call:', x)
class TestClass(metaclass=Meta):
pass
print("-----instance-----")
instance = TestClass(10)
__call__ 的调用时机是使用 TestClass 实例化对象的时候
打印结果:
invoke __new__, cls: <class '__main__.Meta'>
invoke __init__, self: <class '__main__.TestClass'>
-----instance-----
call: 10
元类定义了 __call__ 方法, 那么类就可以被调用(即实例化); 同理, 类中定义了 __call__ 方法, 那么实例就可以被调用
如果 TestClass 中定义了 __call__ 方法, 那么 instance 也可以被调用