出于测试目的,我正在创建我想删除的临时类(在运行其他测试方法之前)。麻烦的是,即使在运行垃圾收集之后,[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
确实在__metaclass__ = abc.ABCMeta
使用@abc.abstractmethod
和Fruit.mass()
装饰器。
剩余的类引用与将Fruit
实例分配给变量有关:如果我删除包含a1
的所有行,则最终Fruit.__subclasses__()
返回{{1 - 即使裸构造函数[]
仍在运行。
这对我来说是一个问题,因为另一个测试涉及水果互动(调用相关的待测方法Apple()
),并且使用blends()
调用来检查不同的组合Fruit.__subclasses__()
的类型。我没有打算定义与这些测试类的交互,这让人感到困惑Fruit
。
有关这些参考文献为什么会留下来的任何提示都将不胜感激。
编辑:如果我在gc.collect()之后调用gc.get_referrers(Apple),我会在赋值之前得到一个“UnboundLocalError:局部变量'Apple'”Fruit使用“@classmethod”定义了许多方法@property“decorators,并引用另一个处理”blends()“的类......
垃圾回收后,blends()
返回
gc.get_referrers(Fruit.__subclasses__()[0])
编辑:当我运行这一个测试方法时会出现问题。 (当我排队多次测试时也会出现这种情况。)我尝试重启我的IDE(PyCharm)并从命令行运行“./manage.py test FruitTests.test_pass_Fruit_core”。尽管特定的内存地址不同,但所有情况都会产生相同的结果。正在直接调用locals() - 我没有在任何地方使用别名。
编辑:定义Fruit的整个模块:
[{'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'>)]
在测试方法中,test_pass_Fruit_core(),“a1 = Apple()”和“a1 = Apple(type ='fuji')”产生相同的结果。将赋值放到“a1”没有任何区别,但如果我将调用放到“locals()”,垃圾收集按预期工作 - Apple在方法结束时不再作为Fruit的子类。
答案 0 :(得分:0)
在垃圾收集环境中,对象的生命周期不是您的责任。因此,你不应该依赖于此。单元测试应测试您的业务逻辑,每个单元测试应测试一个单元的职责。对象的生命周期不是他们的责任,如果你的逻辑依赖于它,那么你要么使用了错误的环境,要么就是在滥用你当前的环境。
或许尝试使用Fruit
或/和Pool
等模式在您的实现中引入“有效”Factory
的概念。如果您从“活动”对象列表中删除一个对象,您将不必担心GS的“不确定性”。
答案 1 :(得分:0)
在对locals()的调用中创建持久引用。要保证“del a1”在“try:”块内创建一个错误不会产生错误,在块之前指定“a1 = None”并跳过对locals()的调用。
最后,工作代码如下。与上面的第一个代码块比较: Apple Apple(Fruit): @staticmethod def质量(大小): 返回大小
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])