我要B
成为某个类的子类 A
,我想覆盖 A.__new__
1。通常,我的代码将具有以下基本结构:
class B(A):
def __new__(cls, ...):
ret = super(B, cls).__new__(cls, ...)
# modify ret as needed
return ret # type(ret) is cls
# ...
这样,type(B(...))
确实是B
. (注意:super(B, cls).__new__(cls, ...)
中的省略号不需要与 B.__new__
的签名中的省略号代表的项目相同。)
但现在假设我想使用某些工厂方法/函数 返回的值A_Factory
(返回 A
类型的对象)作为变量 ret
的起始值在构造函数中。如果我只是这样编码:
class B(A):
def __new__(cls, ...):
ret = A_Factory(...)
# modify ret as needed
return ret # type(ret) is A
...然后type(B(...))
将是 A
, 不是 B
.
设置 ret
类的正确方法是什么?在 B.__new__
的第二个版本中以上,type(B(...))
是B
,更一般地说,对于任何直接或间接子类 C
的 B
, type(C(...))
是C
?
1 我知道通常不需要覆盖父类的 __new__
,但在这里我对需要的不常见情况感兴趣。
最佳答案
您可以设置 __class__
实例的属性是传递给 __new__
的 cls
:
class A(object):
def __init__(self):
self.x = 2
def A_Factory():
return A()
class B(A):
def __new__(cls):
ret = A_Factory()
ret.__class__ = cls # Override the class.
return ret # type(ret) is cls
class C(B):
pass
if __name__ == "__main__":
b = B()
print(b.x)
print(type(b))
print(isinstance(b, B))
print(isinstance(b, A))
c = C()
print(type(C))
输出:
2
<class '__main__.B'>
True
True
<class '__main__.C'>
不过,这有一些限制。 commit that added the ability to assign to __class__
列出它们:
Make
__class__
assignment possible, when the object structures are the same. I hope the test for structural equivalence is stringent enough. It only allows the assignment if the old and new types:
- have the same basic size
- have the same item size
- have the same dict offset
- have the same weaklist offset
- have the same GC flag bit
- have a common base that is the same except for maybe the dict and weaklist (which may have been added separately at the same offsets
in both types)
它们还需要具有相同的 __slots__
,如果您在任一类上定义了它们。实际上,这通常只意味着这两个类都需要在 Python 中实现。尝试使用常规 Python 类和 int
或 tuple
或用 C 实现的其他内容不太可能奏效。
关于python - 如何在不使用 super 的情况下设置 __new__ 返回值的类别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26282774/