2012-08-14 33 views
7

Tôi đã gặp phải thông báo lỗi khá khó hiểu (với tôi ít nhất) khi cố sử dụng trình trang trí để cập nhật trình bao bọc của hàm. Bất kỳ ý tưởng làm thế nào tôi có thể khắc phục điều này?Lỗi gặp phải khi sử dụng trình trang trí để cập nhật trình bao bọc

Tôi đã cố gắng làm cho mã của mình càng chung càng tốt để nó cũng sẽ áp dụng cho các tình huống khác.

def decorator(d): 
    """Make function d a decorator: d wraps a function fn.""" 

    def _d(fn): 
     return functools.update_wrapper(d(fn), fn) 
    functools.update_wrapper(_d, d) 
    return _d 


@decorator 
def f(fn): 
    """Converts the string fn to a function and returns it. 
    Because of the @decorator decorator, _f.__name__ should 
    be identical to f.__name__""" 

    f.__name__ = fn 
    def _f(fn): 
     return eval(fn) 
    return _f 

g = f('x**2') 
print g.__name__ 

đầu ra mong muốn:

>>>x**2 

đầu ra thực tế:

Traceback (most recent call last): 
    File "C:\python\swampy-2.0\testcode.py", line 18, in <module> 
    g = f('x**2') 
    File "C:\python\swampy-2.0\testcode.py", line 6, in _d 
    return functools.update_wrapper(d(fn), fn) 
    File "C:\Python27\lib\functools.py", line 33, in update_wrapper 
    setattr(wrapper, attr, getattr(wrapped, attr)) 
AttributeError: 'str' object has no attribute '__module__' 

Trả lời

5

Một trang trí có một chức năng như một tham số và trả về một "trang trí" chức năng. Bạn đang truyền một chuỗi và cố gắng trả về một hàm thực sự là một nhà máy chức năng. functools.wrapsfunctools.update_wrapper mong đợi một chức năng. Một đối tượng hàm sẽ có thuộc tính __module__ trong khi các cá thể của str không có thuộc tính __module__.

Bạn có muốn tạo hàm từ chuỗi "x ** 2" không?

Việc triển khai decorator của bạn là không cần thiết. Chỉ cần sử dụng functools.wraps:

def f(fn): 
    """Converts the string fn to a function and returns it.""" 
    @functools.wraps(fn) 
    def _f(fn): 
     return eval(fn) 
    return _f 

Tuy nhiên, bạn không muốn trang trí trong trường hợp này nhưng là nhà máy chức năng.

def factory(exp): 
    def f(**kwargs): 
     return eval(exp, globals(), kwargs) 
    f.__name__ = exp 
    return f 

Bây giờ bạn có thể sử dụng như thế này:

>>> x_squared = factory("x**2") 
>>> x_squared(x=7) 
49 

Cảnh báo: Surgeon General đã xác định rằng eval là nguy hiểm đến sức khỏe của bạn

+0

Cảm ơn câu trả lời! Có, tôi biết rõ rằng eval nên được sử dụng hết sức thận trọng :) Trong trường hợp này, mặc dù, tôi nghĩ rằng tôi sẽ gắn bó với nó. Trong trường hợp cụ thể này, điều quan trọng là tôi cũng lưu trữ điểm đến trong _f .__ name___. Nó không có vẻ giống như bất kỳ giải pháp nào cung cấp cho yêu cầu đó. –

+1

Ồ, bạn có thể đặt 'f .__ name__'. Hãy để tôi cập nhật câu trả lời của tôi. – stderr

+0

Trong trường hợp này, những gì _f() đang thực sự làm không thực sự là mối quan tâm chính của tôi (tôi nên đã làm rõ điều đó trong câu hỏi của tôi). Tôi chủ yếu quan tâm đến việc cập nhật hàm wrapper bằng cách sử dụng một trình trang trí. –

Các vấn đề liên quan