2016-02-10 88 views
0

考虑下面的示例类中的Python:Python的析构函数失败构造

class MyClass: 
    def __init__(self, obj): 
     self._obj = obj 

    def __del__(self): 
     if self._obj: 
      print(self._obj) 
在测试套件

,我想检查时调用构造函数不带参数抛出一个异常,即:

c = MyClass() 

有了这个,我得到预期的异常从构造函数:

Traceback (most recent call last): 
    File ".../example.py", line 9, in <module> 
    c = MyClass() 
TypeError: __init__() missing 1 required positional argument: 'obj' 

然而,析构函数也将失败与消息:

Exception ignored in: <bound method MyClass.__del__ of <__main__.MyClass object at 0x0000023D1211CD30>> 
Traceback (most recent call last): 
    File ".../example.py", line 6, in __del__ 
    if self._obj: 
AttributeError: 'MyClass' object has no attribute '_obj' 

据推测,这是因为构造函数没有被调用,因为有一种说法缺少的,因此永远不会创建的属性。

解决这个问题的正确方法是什么?

+0

你有没有一个抽象的例子?如果你真的想要安全,可以使用'getattr'或'try'属性访问。 – jonrsharpe

+1

Python没有析构函数。它确实有终结者。通常,做事的正确方法是避免完全使用它们。 –

+0

值得注意的是'__del__'中产生的异常被忽略。 – Blckknght

回答

2

测试该属性是否实际设置,也通过使其成为类属性来提供默认值。

例如,设置类属性,使你当前的代码工作:

class MyClass: 
    _obj = None # class attribute 

    def __init__(self, obj): 
     self._obj = obj 

    def __del__(self): 
     if self._obj: 
      print(self._obj) 

或使用getattr()带有默认:

def __del__(self): 
    if getattr(self, '_obj', None): 
     print(self._obj) 

返回的第三个参数,如果属性不存在。

+0

这是否意味着'self._obj = obj'行会用一个实例替换class属性? – Nzbuu

+0

不替代,没有。实例属性*掩码*类属性,因为Python首先在实例上查找属性,然后是类,然后是基类。 –

+0

啊,好的。这更有意义。谢谢。 – Nzbuu

1

您可以使用一个类属性:

class MyClass(object): 
    _obj = None 

    def __init__(self, obj): 
     self._obj = obj 

    def __del__(self): 
     if self._obj: 
      print(self._obj) 

这样,总有一个默认的(falsy)值(如果该实例查找失败,类查询会成功)。

就这样说,__del__在python中就像是一只黑羊。一般来说,建议是“不要使用它”的原因有很多。上下文管理器通常是一个稍微更明确的替代品(尽管它们不涵盖所有用例)。