我刚刚将我的课程转换为自我注册"类。这是我第一次涉足python元类。奇怪的是,许多已经过去的测试开始以奇怪的方式失败。许多失败的测试将在自己运行时通过,而不是作为套件的一部分。这让我相信有某种"数据流失"测试之间。所以我创建了一些测试来确定这是否属实,我是对的。
现在的问题是,我该如何解决这个问题。使用del()的tearDown()方法不起作用。添加析构函数( del (self))不起作用。如何取消注册_registry中的项目,以便它们不会交叉污染其他测试?
有趣的是,下面的第一个测试通过,直到我添加第二个测试。
class IterateRegister(type):
def __iter__(cls):
return iter(cls._registry)
class TEST_IterateRegister_instantiation(unittest.TestCase):
class foo(metaclass=IterateRegister):
_registry = []
def __init__(self, name):
self._registry.append(self)
self.name = name
def test__iterate_register_metaclass(self):
names = ['Shaggy', 'Scooby', 'Snack']
x1 = TEST_IterateRegister_instantiation.foo(names[0])
x2 = TEST_IterateRegister_instantiation.foo(names[1])
x3 = TEST_IterateRegister_instantiation.foo(names[2])
self.assertEqual(names, [ f.name for f in TEST_IterateRegister_instantiation.foo ])
def test__destruction_deletes_class_from_registry(self):
names = ['Shaggy', 'Scooby', 'Snack']
x1 = TEST_IterateRegister_instantiation.foo(names[0])
x2 = TEST_IterateRegister_instantiation.foo(names[1])
x3 = TEST_IterateRegister_instantiation.foo(names[2])
del(x2)
names.remove('Scooby')
self.assertEqual(names, [ f.name for f in TEST_IterateRegister_instantiation.foo ])
答案 0 :(得分:1)
在这种情况下,我认为你不需要元类。
class foo(object):
_registry = []
def __init__(self, name):
self._registry.append(self)
self.name = name
为什么不直接迭代_registry
?至于删除x2
,foo._registry
的列表不亚于names
;所以使用.remove
方法。
def test__destruction_deletes_class_from_registry(self):
names = ['Shaggy', 'Scooby', 'Snack']
x1 = self.foo(names[0])
x2 = self.foo(names[1])
x3 = self.foo(names[2])
foo._registry.remove(x2)
names.remove('Scooby')
self.assertEqual(names, [ f.name for f in self.foo._registry ])
答案 1 :(得分:1)
为什么明确使用类名而不是self
?例如:
x1 = TEST_IterateRegister_instantiation.foo(names[0])
x2 = TEST_IterateRegister_instantiation.foo(names[1])
x3 = TEST_IterateRegister_instantiation.foo(names[2])
而不是:
x1 = self.foo(names[0])
x2 = self.foo(names[1])
x3 = self.foo(names[2])
此外,我不认为del
正在按照您的想法行事。所有del
都是remove a bound identifier from the namespace,所以:
del(x2)
相当于写x2 = None
,这不是你想要做的。 Python没有析构函数。字符串是不可变的,对其进行更改不会更改names
。
解决您的问题,听起来您的问题是_registry
是可变的,因此对cls._registry
的更改对所有子类都是可见的。解决此问题的最简单方法是使用设置IterateRegister._registry = []
的拆解方法。但是,我认为你应该重新考虑这个解决方案:如果它在你的测试中已经导致你IterateRegister
持有状态的问题,那么跟踪它是不是很难在生产代码中?