从类继承时,可以通过.__subclasses__()
方法在父类上访问子类。
class BaseClass:
pass
class SubClass(BaseClass):
pass
BaseClass.__subclasses__()
# [<class '__main__.SubClass'>]
但是,删除子类似乎并不能将其从父类中删除。
del SubClass
BaseClass.__subclasses__()
# [<class '__main__.SubClass'>]
__subclasses__
从哪里获得信息?我可以操纵它吗?或
BaseClass.remove_subclass(SubClass)
?答案 0 :(得分:3)
子类在内部包含对其自身的引用,因此它一直存在直到被垃圾回收。如果您强制执行垃圾回收周期,它将从__subclasses__()
中消失:
import gc
gc.collect()
然后它消失了。
但是,在强制垃圾回收之前,请确保已删除对该类的所有其他引用。例如,如果您以交互方式进行操作,并且最后的输出是子类列表,那么在_
中仍将引用该类。
class BaseClass:
pass
class SubClass(BaseClass):
pass
print(BaseClass.__subclasses__())
# [<class '__main__.SubClass'>]
del SubClass
import gc
gc.collect()
print(BaseClass.__subclasses__())
# []
使用python 3.7的输出是:
[<class '__main__.SubClass'>]
[]
我可能还应该补充一点,虽然垃圾收集在这种简单情况下起作用,但您可能不应该在现实生活中依赖它:意外地在代码中的某个地方意外引用子类,然后想知道这太容易了。为什么班级永远不会消失。
您要在此处进行的操作是保留子类的注册表,以便工厂可以返回适当类的对象。如果您希望能够从注册表中添加和删除类,那么我认为您必须明确。您仍然可以使用__subclasses__
查找候选类,但是在每个类上保留一个标志以显示是否已启用。然后,不只是删除子类,而是设置标志以显示该类不再使用,然后(如果需要)将其删除。
答案 1 :(得分:0)
__subclasses__
从哪里获取信息?
对于Python的CPython实现,类型对象在PyTypeObject.tp_subclasses
下保留一个弱引用列表。在文档中将其标记为“未继承。仅供内部使用” ,因此可以将其视为CPython的实现细节。另请参阅:How is __subclasses__
method implemented in CPython?。
我可以操纵它吗?
任何类都有一个.__bases__
描述符,如果更改,它会更新PyTypeObject.tp_subclasses
中的引用。
.__bases__
时,只能操纵 object
。因此,当:
class BaseClass: pass
class OtherClass(BaseClass): pass
和
class BaseClass: pass
class OtherClass: pass
BaseClass.__bases__ = (OtherClass, )
# TypeError: __bases__ assignment: 'BaseClass' deallocator differs from 'object'
应等效为*。您会得到一个错误。参见:https://bugs.python.org/issue672115
您也不能使用它来更改从对象继承的类。
class BaseClass: pass
class SubClass(BaseClass): pass
SubClass.__bases__ = (object,)
# TypeError: __bases__ assignment: 'type' object layout differs from 'BaseClass'
但是,您可以将一个类的基础更改为另一个类。
class BaseClass: pass
class SubClass(BaseClass): pass
class OtherClass: pass
SubClass.__bases__ = (OtherClass, )
# Or don't define it.
SubClass.__bases__ = (type("OtherClass", (object, ), {}), )
这全部更新了父类:
>>> BaseClass.__subclasses__()
[]