Python 3 metaclass 定义的函数在从 metaclass 派生的 class 中不可见

Python 3 metaclass defined functions not visible in the class derived from metaclass

我正在研究基于 python 3 的元class,据我所知,元class typedef

个 class。这是一个小例子

class smallClass(type):

    def __init__(self, clsname, bases, clsdict):
        super(smallClass, self).__init__(clsname, bases, clsdict)
        self.a = 10
        self.b = 15
        print(self.addnos())

    def addnos(self):
        return self.a + self.b

    def __new__(self, clsname, bases, clsdict):
        return super(smallClass, self).__new__(self, clsname, bases, clsdict)

class smallClass2(object, metaclass=smallClass):
    la = smallClass.addnos

clstest = smallClass2()

clstest.addnos() ''' this does not work:  AttributeError: 'smallClass2' object has no attribute 'addnos'  '''

奇怪的是函数 addnos 在 smallClass2 中是不可见的,即使它基于包含 addnos 函数的元class smallClass

有人可以帮助理解如何访问 metaclass 中定义的函数吗?或者为什么 clstest.addnos() 不起作用?

函数 addnos 可以从 metaclass 访问,但不能从派生 class 访问,为什么?

这里换一个试试,有同样的问题

class smallClass(type):


    def __init__(self, clsname, bases, clsdict):
        super(smallClass, self).__init__(clsname, bases, clsdict)
        self.a = 10
        self.b = 15
        print(self.addnos())

    def addnos(self):
        return self.a + self.b

    def __new__(self, clsname, bases, clsdict):
        return super(smallClass, self).__new__(self, clsname, bases, clsdict)


class smallClass2(object, metaclass=smallClass):
    pass

clstest = smallClass2()
clstest.addnos()

我完全不明白你的意图,以及你是否真的需要元class。但这是正在发生的事情:

Python 中的元class 是一个class-对象class。我认为通过 (iPython) 终端上的示例很容易将其可视化:

In [1]: class A:
   ...:    pass
   ...: 
   ...: a = A()
   ...: 

In [2]: type(a)
Out[2]: __main__.A

In [3]: type(A)
Out[3]: type

此时"A",type(a)返回的是对象"a"的class,[=49=返回的"type" ] 是对象 "A" 的 class - 诀窍是在 Python 中甚至 classes 都是对象:它们都是 "type" 或一个的实例"type" 的子类型。 "class of a class" 的作用就是所谓的 "metaclass"。

当您从 "type" 继承时,您创建的 class 的实例将是 class 本身。并且以 class 语句上的 "named parameter" 的形式,对 class 主体的 select 元 class 提供语法支持。

综上所述,这就是属性检索在 Python 中的工作方式(缩短版本 - 我不会进入 "descriptors" 或添加很多步骤的 setattr、getattr 和 getattribute 机制):

当您请求对象的属性时,Python 首先 (*) 查看该对象的 __dict__ 属性,如果它包含所请求的属性,则该属性必须是映射。如果不是,它会在对象的 class 上查找属性(也在 class __dict__ 上)。如果对象的 class 没有属性,Python 会在对象的 superclasses 上寻找它 - 但它确实不要进入 class'class 来查找属性。 (它遵循 metaclasses,因为它们最终出现在 class __mro__ 属性中)。

所以,如果我这样做:

class MyMeta(type):
   test = "value from metaclass"
   other_test = "Other metaclass value"

class A:
   test = "value from ancestor class"

class B(A, metaclass=MyMeta):
   pass

b = B()

对于实例"b",Python可以找到"A"中定义的"test",但永远不会自动找到"test"中定义的"test" "MyMeta",也不会看到"other_test"。这就是您的代码中发生的事情。

如果需要从实例值中查看元class中定义的值,则只需逐步执行 class - 因此,如果 B 中的方法想要到达上面的 "other_test",这将起作用:

class B(A, metaclass=MyMeta):
   def method(self):
        print(self.__class__.other_test)

(不是 test,但仍会被 A 中祖先 class 中定义的 test 遮蔽)

总而言之,我发现无论您在那里尝试什么,您实际上都不太可能需要元class。它看起来更像是您想要简单 class 继承的行为。

(*) 始终牢记这是对属性查找算法的超级简化描述。第一次查找属性实际上是在实例的 class 本身中,查找 "descriptor" 对象。