为什么类会拥有其元类的属性?

最近在学习Python的一些设计模式,当看到用元类实现单例模式代码的时候,发现一个很有意思的问题,先看代码:

class Meta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = type.__call__(cls, *args, **kwargs)
        return cls._instances[cls]

问题是_instances不是元类的属性吗?为什么可以通过cls._instances来访问?
stackoverflow有人曾提过相同的问题,点这里可以看

编写了一些实验的代码,如下:

class TopMeta(type):
    topmeta = 'topmeta'

class MetaBaseCls:
    metabasecls = 'metabasecls'
    
class UpperMeta(type, MetaBaseCls, metaclass=TopMeta):
    uppermeta = 'uppermeta'
    attr = 'uppermeta attr'

class BaseCls:
    basecls='basecls'
    attr = 'basecls attr'

class C(BaseCls, metaclass=UpperMeta):
    pass


C.basecls
C.uppermeta
C.metabasecls
C.attr
try:
    print(C.topmeta)
except Exception as e:
    print(e)

输出为:

'basecls'

'uppermeta'

'metabasecls'

'basecls attr'

type object 'C' has no attribute 'topmeta'

根据上面的实验,可以发现:

  1. C会先在自身的继承链里查找,所以打印basecls attr,而不是uppermeta attr。
  2. uppermeta和metabasecls都在其元类的继承链中,所以都可以找到。
  3. topmeta是其元类的元类,并不在其元类的继承链中,找不到,会报错。

具体的实现细节没有完全弄清楚,但简单总结一些规律:
对象(注意这个对象包含实例和类)会先在自己的整个继承链里面寻找属性,如果没有找到,则会在它的类的继承链里面寻找属性,而类是元类的实例,换句话说,类的类是元类。所以类会先在自身的继承链里面查找属性,如果找不到,则到它的元类的继承链里面查找属性。

这里容易想不通的是按照以上解释,实例的继承链不就是其类的继承链吗?那不是重复了?
个人是这样理解,实例是通过object类创造出来,类是通过type类创造出来,所以本质上说实例和类是不同的东西,类有继承链,实例没有,只有自身的命名空间。所以对于实例来说,先在自己的命名空间里面查找属性,找不到,再在其类的继承链里寻找属性。
如果有不对的地方,请大家指出。

猜你喜欢

转载自www.cnblogs.com/telecomshy/p/9297086.html