为了测试目的,我正在创建临时类,我想删除这些类(在其他测试方法运行之前)。问题是,即使在运行垃圾收集之后,[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__()调用来检查不同类型Fruit的组合。我没有费心定义与这些测试类的交互,这让blends()很困惑。
任何提示,为什么这些参考资料停留在附近,将不胜感激。
编辑:如果我在gc.collect()之后调用gc.collect(Apple),我会得到一个"UnboundLocalError:局部变量'Apple‘在赋值前引用的“UnboundLocalError定义了许多方法,其中包含了"@classmethod”和"@property“装饰器,并引用了另一个类,该类处理”复合()“.
在垃圾收集之后,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 e.py测试FruitTests.test_pass_Fruit_core“。虽然特定的内存地址不同,但所有情况都会产生相同的结果。当地人()被直接调用--我在任何地方都没有它的别名。
编辑:定义水果的整个模块:
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“并没有什么区别,但是如果我放弃对”局部变量()“的调用,垃圾收集就会像预期的那样工作--在方法的末尾,苹果不再是果树的子类。
发布于 2014-02-25 23:42:23
持久引用是在对局部变量()的调用中创建的。为了保证"del a1“不生成错误,如果在"try:”块中创建了一个错误,则在块之前分配"a1 = None“,并跳过对局部变量的调用。
最后,工作代码如下。与上面的第一个代码块比较:类Apple(果树):@staticmethod def质量( size ):返回大小
class Orange(Fruit):
@staticmethod
def mass(size):
return size
a1 = None
try:
Apple()
Orange()
a1 = Apple(type='fuji')
finally:
del a1
print gc.get_referrers(Apple)
print gc.get_referrers(Orange)
del Apple
del Orange
print Fruit.__subclasses__()
gc.collect()
sc = Fruit.__subclasses__()
print sc
if len(sc) > 0:
print 42, gc.get_referrers(sc[0])发布于 2014-02-25 23:16:00
在垃圾收集环境中,对象的生命时间不是您的责任。正因为如此,你不应该依赖这个。单元测试应该测试您的业务逻辑,每个单元测试应该测试一个单元的职责。对象生命时间不可能是他们的责任,如果您的逻辑依赖于它,那么要么您使用了错误的环境,要么您滥用了您当前的环境。
也许尝试在您的实现中引入一个“活动”Fruit的概念,使用Pool或/和Factory之类的模式。如果要从“活动”对象列表中删除一个对象,就不必担心GS的“不确定性”。
https://stackoverflow.com/questions/22027521
复制相似问题