我正在研究一个基于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()
答案 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
遮蔽
所有人都说,我发现你在那里尝试的任何东西都很可能需要一个元类。它看起来更像是你想要简单类继承的行为。
(*)始终牢记这是对属性查找算法的超简化描述。对属性的第一次查找实际上是在实例的类本身中,寻找“描述符”对象。