下面是一个在Python 2.7中工作但在Python 3.6中导致错误的可执行代码:
import six
class AMeta(type):
def __new__(cls, name, bases, attrs):
module = attrs.pop('__module__')
new_attrs = {'__module__': module}
classcell = attrs.pop('__classcell__', None)
if classcell is not None:
new_attrs['__classcell__'] = classcell
new = super(AMeta, cls).__new__(
cls, name, bases, new_attrs)
new.duplicate = False
legacy = super(AMeta, cls).__new__(
cls, 'Legacy' + name, (new,), new_attrs)
legacy.duplicate = True
return new
@six.add_metaclass(AMeta)
class A():
def pr(cls):
print('a')
class B():
def pr(cls):
print('b')
class C(A,B):
def pr(cls):
super(C, cls).pr() # not shown with new_attrs
B.pr(cls)
print('c') # not shown with new_attrs
c = C()
c.pr()
# Expected result
# a
# b
# c
我得到以下错误:
Traceback (most recent call last):
File "test.py", line 28, in <module>
class C(A,B):
TypeError: __class__ set to <class '__main__.LegacyC'> defining 'C' as <class '__main__.C'>
C是从用元类AMeta生成的A继承的。它们是测试类,AMeta的目标是使用两个不同的文件夹执行所有测试:默认文件夹和遗留文件夹。你知道吗
我找到了一种方法来消除这个错误,从attrs中删除classcell,然后返回new=super(AMeta,cls)。new(cls,name,base,attrs)(不是new\u attrs),但它似乎不对,如果不对,我想知道原因。你知道吗
新属性的目标来自于这个SO question或documentation,它的状态基本上是相反的:在修改属性时,请确保保留classcell,因为它在Python3.6中不受欢迎,并且会导致Python3.8中的错误。 请注意,在这种情况下,它会删除pr定义,因为它们没有传递给新的属性,因此打印“b”而不是“abc”,但与此问题无关。你知道吗
有没有办法在元类AMeta的new内部调用多个super()。new,然后从继承a的类继承的类C调用它们?你知道吗
如果没有嵌套继承,则不会出现错误,如下所示:
import six
class AMeta(type):
def __new__(cls, name, bases, attrs):
new = super(AMeta, cls).__new__(
cls, name, bases, attrs)
new.duplicate = False
legacy = super(AMeta, cls).__new__(
cls, 'Duplicate' + name, (new,), attrs)
legacy.duplicate = True
return new
@six.add_metaclass(AMeta)
class A():
def pr(cls):
print('a')
a = A()
a.pr()
# Result
# a
那么也许是A的角色做些什么来修复它?你知道吗
提前谢谢
你的问题是什么,以及如何解决 问题是,当您做您正在做的事情时,您将相同的
cell
对象传递给类的两个副本:原始副本和遗留副本。你知道吗由于它同时存在于两个类中,当一个人试图使用它时,它会与它正在使用的另一个地方发生冲突-
super()
在调用时会选择错误的祖先类。你知道吗cell
对象很挑剔,它们是用本机代码创建的,不能在Python端创建或配置。我可以找到一种方法来创建类副本,方法是返回一个fresh cell对象,并将其作为__classcell__
传递。你知道吗(我还试着在
classcell
对象上运行copy.copy
/copy.deepcopy
然后再使用下面的cellfactory
吼叫-它不起作用)为了重现问题并找出解决方案,我制作了一个更简单的元类版本,Python3 only。你知道吗
因此,我不仅创建了一个嵌套函数,以便让Python运行时创建一个单独的cell对象,然后在克隆类中使用它,而且还必须使用指向新cell var的新的
__closure__
重新创建使用cell类的方法如果不重新创建这些方法,它们将无法在clonned类中工作,因为克隆类中的
super()
方法将期望单元格指向克隆类本身,但它指向原始类。你知道吗幸运的是,Python3中的方法是普通函数,这使得代码更简单。但是,该代码不会在Python2中运行-因此,只需将其包含在一个
if
块中,就不会在Python2上运行了。因为__cellclass__
属性甚至不存在,所以根本没有问题。你知道吗将上面的代码粘贴到Python shell中后,我可以运行这两个方法并且
super()
可以工作:相关问题 更多 >
编程相关推荐