如何从__subclasses__中删除类?

时间:2018-09-20 15:36:35

标签: python python-3.x class subclass

从类继承时,可以通过.__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)

2 个答案:

答案 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__()
[]