Python metaclass 元类

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)

以上代码块的执行流程为:

  1. 遇到第一个 class 语句, 相当于执行 Meta = type('Meta', (type,), {'__new__': xxx}), 结果是创建了一个元类 Meta

  2. 遇到第二个 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 也可以被调用

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值