我希望能够跟踪几何点对象的实例,以便知道在自动命名新对象时已经“使用”了哪些名称。在
例如,如果已创建名为“A”、“B”和“C”的点,则下一个自动命名的点将命名为“D”。如果名为“D”的点被删除,或其引用丢失,则名称“D”将再次可用。在
我的Point
对象的主要属性被定义为属性,它们是相当标准的x
、y
和{
我按照描述的here,使用了weakref.WeakSet()
。我将此添加到我的Point
类中:
# class attribute
instances = weakref.WeakSet()
@classmethod
def names_in_use(cls):
return {p.name for p in Point.instances}
问题是,当我实例化一个点然后删除它时,它大部分时间都是从Point.instances
中删除的,但并非总是总是。我注意到,如果我运行测试套件(pytest -x -vv -r w
),那么如果在测试中引发了某个异常,则实例从不被删除(可能的解释将在下面阅读)。在
在下面的测试代码中,在第一次删除p
之后,它总是从Point.instances
中删除,但是在第二次删除{assert
语句失败:
结果是:
tests/04_geometry/01_point_test.py::test_instances FAILED
=============================================================================== FAILURES ===============================================================================
____________________________________________________________________________ test_instances ____________________________________________________________________________
def test_instances():
import sys
p = Point(0, 0, 'A')
del p
sys.stderr.write('1 - Point.instances={}\n'.format(Point.instances))
assert len(Point.instances) == 0
assert Point.names_in_use() == set()
p = Point(0, 0, 'A')
with pytest.raises(TypeError) as excinfo:
p.same_as('B')
assert str(excinfo.value) == 'Can only test if another Point is at the ' \
'same place. Got a <class \'str\'> instead.'
del p
sys.stderr.write('2 - Point.instances={}\n'.format(Point.instances))
> assert len(Point.instances) == 0
E assert 1 == 0
E + where 1 = len(<_weakrefset.WeakSet object at 0x7ffb986a5048>)
E + where <_weakrefset.WeakSet object at 0x7ffb986a5048> = Point.instances
tests/04_geometry/01_point_test.py:42: AssertionError
------------------------------------------------------------------------- Captured stderr call -------------------------------------------------------------------------
1 - Point.instances=<_weakrefset.WeakSet object at 0x7ffb986a5048>
2 - Point.instances=<_weakrefset.WeakSet object at 0x7ffb986a5048>
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================================= 1 failed, 82 passed in 0.36 seconds ==================================================================
但是,在捕获异常中测试的代码不会创建新的点实例:
def same_as(self, other):
"""Test geometric equality."""
if not isinstance(other, Point):
raise TypeError('Can only test if another Point is at the same '
'place. Got a {} instead.'.format(type(other)))
return self.coordinates == other.coordinates
坐标基本上是:
@property
def coordinates(self):
return (self._x, self._y)
其中_x
和{
原因似乎是(引自python's doc):
CPython implementation detail: It is possible for a reference cycle to prevent the reference count of an object from going to zero. In this case, the cycle will be later detected and deleted by the cyclic garbage collector. A common cause of reference cycles is when an exception has been caught in a local variable.
将此方法添加到Point
类:
def untrack(self):
Point.instances.discard(self)
而在del myPoint
之前使用myPoint.untrack()
(或者在以另一种方式失去对点的引用之前)似乎可以解决这个问题。在
但是每次都要打电话给untrack()
,这是相当沉重的。。。例如,在我的测试中,我需要“取消跟踪”许多点,以确保所有名称都可用。在
有没有更好的方法来跟踪这些实例?(通过改进这里使用的跟踪方法,或者通过其他更好的方法)。在
不要试图基于整个程序中存在的所有
Point
对象跟踪可用名称。预测哪些对象将存在以及何时对象将停止存在是困难且不必要的,而且在不同的Python实现中,它的行为也会非常不同。在首先,为什么要强制点名称的唯一性?例如,如果您在某个窗口中绘制地物,但不希望在同一地物中有两个具有相同标签的点,则让地物跟踪其中的点,并拒绝具有所取名称的新点。这也便于从地物中显式删除点,或使两个地物具有独立的点名称。在许多其他上下文中,类似的显式容器对象可能是合理的。在
如果这些是未附着到某些几何体环境的自由浮点,那么为什么要命名它们呢?如果我想在(3.5,2.4)处表示一个点,我不在乎我把它命名为a、B还是Bob,我当然不希望崩溃,因为程序中途的某个地方的其他代码也决定将它们的点命名为Bob。为什么名称或名称冲突很重要?在
我不知道您的用例是什么,但是我可以想象,最好是在显式容器中只强制名称唯一性,或者根本不强制名称唯一性。在
相关问题 更多 >
编程相关推荐