2011-10-09 33 views
10

Tôi đang viết một trình trang trí hàm sẽ áp dụng một chuyển đổi cho đối số đầu tiên của hàm. Nó hoạt động tốt nếu tôi chỉ trang trí các chức năng của tôi một lần nhưng nếu tôi trang trí cho họ hai lần tôi nhận được một lỗi. Dưới đây là một số mã chứng minh vấn đề, đó là một phiên bản đơn giản của mã tôi đang làm việc. Tôi đã loại trừ các mã mà không được chuyển đổi để không phân tâm từ vấn đềTrang trí hàm lồng nhau hoạt động trên các đối số trong python

from inspect import getargspec 
from functools import wraps 

def dec(id): 
    def _dec(fn): 
     @wraps(fn) 
     def __dec(*args, **kwargs): 
      if len(args): 
       return fn(args[0], *args[1:], **kwargs) 
      else: 
       first_arg = getargspec(fn).args[0] 
       new_kwargs = kwargs.copy() 
       del new_kwargs[first_arg] 
       return fn(kwargs[first_arg], **new_kwargs) 
     return __dec 
    return _dec 

@dec(1) 
def functionWithOneDecorator(a, b, c): 
    print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c) 

@dec(1) 
@dec(2) 
def functionWithTwoDecorators(a, b, c): 
    print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c) 

functionWithOneDecorator(1, 2, 3) 
functionWithOneDecorator(1, b=2, c=3) 
functionWithOneDecorator(a=1, b=2, c=3) 
functionWithOneDecorator(c=3, b=2, a=1) 

functionWithTwoDecorators(1, 2, 3) 
functionWithTwoDecorators(1, b=2, c=3) 
functionWithTwoDecorators(a=1, b=2, c=3) 
functionWithTwoDecorators(c=3, b=2, a=1) 

Khi tôi chạy đoạn mã trên tôi nhận được kết quả như sau:

functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithTwoDecorators(a = 1, b = 2, c = 3) 
functionWithTwoDecorators(a = 1, b = 2, c = 3) 
IndexError: list index out of range 

Điều này là do khi trang trí thứ hai kiểm tra chức năng đó là trang trí để tìm các tên đối số và thất bại vì nó là trang trí một trang trí và chỉ mất * args và ** kwargs.

Tôi có thể nghĩ ra các cách xung quanh vấn đề sẽ hoạt động trong mã ở trên nhưng vẫn sẽ bị hỏng nếu một hàm được trang trí với trang trí của tôi và một chức năng khác từ bên thứ ba. Có cách nào chung để sửa lỗi này? hoặc có cách nào tốt hơn để đạt được kết quả tương tự không?

Cập nhật: Nhờ @Hernan chỉ ra decorator module. Nó giải quyết vấn đề này chính xác. Bây giờ mã của tôi trông giống như sau:

from decorator import decorator 

def dec(id): 
    @decorator 
    def _dec(fn, *args, **kwargs): 
     return fn(args[0], *args[1:], **kwargs) 
    return _dec 

@dec(1) 
def functionWithOneDecorator(a, b, c): 
    print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c) 

@dec(1) 
@dec(2) 
def functionWithTwoDecorators(a, b, c): 
    print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c) 

functionWithOneDecorator(1, 2, 3) 
functionWithOneDecorator(1, b=2, c=3) 
functionWithOneDecorator(a=1, b=2, c=3) 
functionWithOneDecorator(c=3, b=2, a=1) 

functionWithTwoDecorators(1, 2, 3) 
functionWithTwoDecorators(1, b=2, c=3) 
functionWithTwoDecorators(a=1, b=2, c=3) 
functionWithTwoDecorators(c=3, b=2, a=1)  

Sạch hơn và hoạt động!

+1

Tại sao 'args [0], * args [1:]', nó giống với '* args'? –

+0

Bạn đang cố gắng giải quyết vấn đề gì với người trang trí này? Theo như tôi có thể nói đó là mục tiêu chính có vẻ là để đảm bảo rằng đối số đầu tiên được đưa ra - từ khóa/tùy chọn hoặc cách khác - được chuyển cho hàm được bao bọc vì đó là đối số "đầu tiên". Ngoài ra, ý nghĩa dự định của đối số 'id' đối với người trang trí là gì? Nó không được sử dụng ở bất cứ đâu. –

+0

Tôi muốn áp dụng một chuyển đổi cho đối số đầu tiên. Trong mã được cung cấp ở trên, tôi đã loại trừ mã thực hiện chuyển đổi để không làm sao lãng vấn đề. –

Trả lời

5

Vấn đề là chữ ký của chức năng trang trí của bạn không phải là chữ ký (getargspec) từ bản gốc. Nó thực sự được giải thích rõ ràng trong sự giúp đỡ của decorator module mà bạn có thể giải quyết vấn đề của mình. Về cơ bản, bạn nên sử dụng một trang trí bảo quản chữ ký, để trang trí thứ hai nhìn thấy chữ ký giống như chữ ký đầu tiên.

+0

Rực rỡ, đó chính xác là những gì tôi đang tìm kiếm. –

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