【发布时间】:2014-02-25 22:21:47
【问题描述】:
出于测试目的,我正在创建要删除的临时类(在其他测试方法运行之前)。麻烦的是,[superclass].__subclasses__() 仍然会列出已删除的类,即使在运行垃圾回收之后也是如此。
这是我的测试方法的样子:
class Apple(Fruit):
@staticmethod
def mass(size):
return size
class Orange(Fruit):
@staticmethod
def mass(size):
return size
try:
Apple()
Orange()
a1 = Apple(type='fuji')
finally:
if 'a1' in locals():
print 'del a1'
del a1
print gc.get_referrers(Apple)
print gc.get_referrers(Orange)
del Apple
del Orange
print Fruit.__subclasses__()
gc.collect()
print Fruit.__subclasses__()
输出如下:
del a1
[<frame object at 0xabcdef0>, (<class 'Apple'>, <class 'Fruit'>, <type 'object'>), <Apple object at 0x4443331>, {'a1': <Apple object at 0x4443331, 'self': <FruitTests testMethod=test_pass_Fruit_core>, 'Orange': <class 'Orange'>, 'Apple': <class 'Apple'>}]
[<frame object at 0xabcdef0>, (<class 'Orange'>, <class 'Fruit'>, <type 'object'>), {'a1': <Apple object at 0x4443331, 'self': <FruitTests testMethod=test_pass_Fruit_core>, 'Orange': <class 'Orange'>, 'Apple': <class 'Apple'>}]
[<class 'Apple'>, <class 'Orange'>]
[<class 'Apple'>, <class 'Orange'>]
所涉及的所有类都没有明确定义的__del__(),尽管Fruit 确实在Fruit.mass() 上使用了__metaclass__ = abc.ABCMeta 和@abc.abstractmethod 装饰器。
剩余的类引用与将Fruit 实例分配给变量有关:如果我删除所有包含a1 的行,则最终的Fruit.__subclasses__() 返回[] - 即使是裸构造函数Apple() 仍在运行。
这对我来说是个问题,因为另一个测试与水果交互有关(调用相关的待测试方法blends()),并且使用Fruit.__subclasses__() 调用来检查不同类型@987654336 的组合@。我没有费心定义与这些测试类的交互,这让blends() 感到困惑。
任何关于为什么这些参考文献仍然存在的提示将不胜感激。
编辑:如果我在 gc.collect() 之后调用 gc.get_referrers(Apple),我会得到一个“UnboundLocalError: local variable 'Apple' referenced before assignment”Fruit 使用“@classmethod”和“ @property" 装饰器,并引用另一个处理 "blends()" 的类...
垃圾回收后,gc.get_referrers(Fruit.__subclasses__()[0]) 返回
[{'a1': <Apple object at 0x4443331>, 'self': <FruitTests testMethod=test_pass_Fruit_core>, 'Orange': <class 'Orange'>, 'Apple': <class 'Apple'>}, <Apple object at 0x4443331>, (<class 'Apple'>, <class 'Fruit'>, <type 'object'>)]
编辑:当我只运行这一种测试方法时会出现问题。 (当我排队多个测试时也会发生这种情况。)我尝试重新启动我的 IDE(PyCharm)并从命令行运行“./manage.py test FruitTests.test_pass_Fruit_core”。尽管特定的内存地址有所不同,但所有情况都会产生相同的结果。 locals() 被直接调用 - 我没有在任何地方使用别名。
编辑:定义 Fruit 的整个模块:
from abc import abstractmethod, ABCMeta
class Fruit(object):
__metaclass__ = ABCMeta
def __init__(self, **kwargs):
super(Fruit, self).__init__()
@abstractmethod
def mass(self, size):
raise NotImplementedError
在测试方法中,test_pass_Fruit_core()、“a1 = Apple()”和“a1 = Apple(type='fuji')”产生相同的结果。放弃对“a1”的分配没有什么区别,但如果我放弃对“locals()”的调用,垃圾收集将按预期工作——在方法结束时,Apple 不再作为 Fruit 的子类使用。
【问题讨论】:
-
垃圾回收后
gc.get_referrers(Apple)会打印什么? -
对子类的引用是弱引用,所以 something else 仍然是指这些类。 ABC 架构也包含引用,再次使用弱引用。
-
使用
gc.gen_referrers(Fruit.__subclasses__()[0])。 -
那么,是否还有另一个
FruitTests.test_pass_Fruit_core测试方法在某个地方保留着另一个这些子类的集合?或者您是否将locals()的输出存储在某处,看起来像locals()字典。
标签: python unit-testing garbage-collection subclassing