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" 对象。
我正在研究基于 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" 对象。