2016-04-05 44 views
0

我有一个属性有一个断言来检查值是否是str类型。在Python中处理属性上的装饰器的异常

为了抓住这个assertionError,我根据我在网上找到的例子创建了一个装饰器。

装饰:

def catch_assertionerror(function): 
    def handle_problems(*args, **kwargs): 
     try: 
      return function(*args, **kwargs) 
     except AssertionError: 
      # log_error(err.args[0]) 
      print "error caught" 
    return handle_problems 

物业:

@catch_assertionerror 
@name.setter 
def name(self, value): 
    assert isinstance(value, str), "This value should be a string" 
    self._name = name 

设置name属性:

self.name = self.parse_name_from_xml() 

当我运行这段代码,没有显示出任何错误,所以我想它被捕获,但另一方面,错误消息不会被打印到屏幕上。

然后我尝试一种更简单的例子,我在Stachoverflow发现:

def handleError(function): 
    def handleProblems(): 
     try: 
      function() 
     except Exception: 
      print "Oh noes" 
    return handleProblems 


@handleError 
def example(): 
    raise Exception("Boom!") 

这也处理的错误,但没有打印错误信息到屏幕上。

有人可以向我解释我在这里失踪了什么吗?

+1

您没有在代码中显示调用函数的位置 – hspandher

+0

我刚刚在交互式Python会话中尝试了“更简单的示例”,并且它按预期工作。你如何运行这些代码? – SpoonMeiser

回答

4

你的后一个例子对我的作品,但你的主要问题在于,你没有在

@catch_assertionerror 
@name.setter 
def name(self, value): 
    assert isinstance(value, str), "This value should be a string" 
    self._name = name 

descriptor包装与catch_assertionerror功能。更糟糕的是,你会返回一个函数,而不是包装原始文件的新描述符。现在,当您分配给name属性时,只需使用指定的值替换包装函数即可。

一步一步,使用原来的类定义:

class X(object): 

    @property 
    def name(self): 
     return self._name 

    @catch_assertionerror 
    @name.setter 
    def name(self, value): 
     assert isinstance(value, str), "This value should be a string" 
     self._name = value 

>>> x = X() 
>>> x.name 
<unbound method X.handle_problems> 
>>> x.__dict__ 
{} 
>>> x.name = 2 
>>> x.name 
2 
>>> x.__dict__ 
{'name': 2} 

你必须做什么是包裹方法函数来代替,然后把它传递给描述符处理装饰:

class X(object): 
    @property 
    def name(self): 
     return self._name 
    @name.setter 
    @catch_assertionerror 
    def name(self, value): 
     assert isinstance(value, str), "This value should be a string" 
     self._name = value 

等:

>>> x = X() 
>>> x.name 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in name 
AttributeError: 'X' object has no attribute '_name' 
>>> x.name = 2 
error caught 
>>> x.name = "asdf" 
>>> x.name 
'asdf' 

将来考虑使用functools.wrapsfunctools.update_wrapper。没有他们你的类和函数更难检查,因为你的包装将隐藏原始:

>>> @catch_assertionerror 
... def this_name_should_show(): pass 
... 
>>> this_name_should_show 
<function handle_problems at 0x7fd3d69e22a8> 

定义你的装饰是这样的:

def catch_assertionerror(function): 
    @wraps(function) 
    def handle_problems(*args, **kwargs): 
     ... 
    return handle_problems 

将保留原有功能的信息:

>>> @catch_assertionerror 
... def this_name_should_show(): pass 
... 
>>> this_name_should_show 
<function this_name_should_show at 0x7fd3d69e21b8> 

它也会向您表明您的情况存在问题:

# When trying to define the class 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 6, in X 
    File "<stdin>", line 2, in catch_assertionerror 
    File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper 
    setattr(wrapper, attr, getattr(wrapped, attr)) 
AttributeError: 'property' object has no attribute '__module__'