Python 3元类定义的函数在从元类派生的类中不可见

时间:2017-06-01 20:59:47

标签: python-3.x metaclass

我正在研究一个基于python 3的元类,因为我理解元类一个typedef

班级。这是一个小例子

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函数的元类smallClass

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

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

这里另一个替代尝试,有同样的问题

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()

1 个答案:

答案 0 :(得分:0)

我无法理解你的意图是什么,以及你是否真的需要一个元类。但这是正在发生的事情:

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

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

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

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

在这种情况下,type(a)返回的“A”是对象“a”的类,“type(A)”返回的“type”是对象“A”的类 - 诀窍是在Python中甚至类都是对象:它们都是“类型”的实例或“类型”的子类型。 “阶级”这个角色被称为“元类”。

当你从“type”继承时,你创建的类的实例将是类本身。语言的语法支持,以类声明中的“命名参数”的形式,为类体选择元类。

所有这一切,这就是属性检索在Python中的工作原理(缩短版本 - 我不会进入“描述符”或添加了很多步骤的setattr,getattr和getattribute机制):

当您从对象请求属性时,Python first(*)会查看该对象的__dict__属性,如果它包含所请求的属性,则该属性必须是映射。如果没有,它会在对象的类上查找属性(同样在类__dict__上)。如果对象的类没有该属性,Python会在对象的超类上查找它 - 但它不会进入类'类来查找属性。 (它遵循元类,因为它们在类__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”,但它永远不会自动找到“MyMeta”中定义的“test”,也不会看到“other_test”。这就是您的代码中发生的事情。

如果需要从实例值中看到它们是在元类中定义的,那么所有人必须做的就是逐步完成类 - 所以,如果B中的方法想要到达上面的“other_test”,这将是工作:

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

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

所有人都说,我发现你在那里尝试的任何东西都很可能需要一个元类。它看起来更像是你想要简单类继承的行为。

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