2016-10-07 18 views
6

Tôi đang cố gắng viết một trình trang trí giữ nguyên các đối số của các hàm mà nó trang trí. Động cơ để làm điều này là viết một trang trí tương tác độc đáo với pytest.fixtures.Python tạo các đối số chức năng bảo quản trang trí

Giả sử chúng tôi có chức năng foo. Phải có một đối số a.

def foo(a): 
    pass 

Nếu chúng ta có được spec đối số của foo

>>> inspect.getargspec(foo) 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None) 

Chúng tôi thường muốn tạo một trang trí nơi wrapper chức năng vượt qua tất cả các đối số của nó đúng nguyên văn để các wrapped chức năng. Cách rõ ràng nhất để thực hiện việc này là sử dụng *args**kwargs.

def identity_decorator(wrapped): 
    def wrapper(*args, **kwargs): 
     return wrapped(*args, **kwargs) 
    return wrapper 

    def identity_decorator(wrapped): 
    def wrapper(*args, **kwargs): 
     return wrapped(*args, **kwargs) 
    return wrapper 

@identity_decorator 
def foo(a): 
    pass 

này, không đáng ngạc nhiên, tạo ra một chức năng với một spec lập luận phản ánh *args**kwargs.

>>> inspect.getargspec(foo) 
ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None) 

Có cách nào thay đổi thông số đối số để khớp với hàm được bao bọc hoặc tạo hàm có thông số đối số phù hợp ban đầu không?

+2

Tôi nghĩ rằng trong các phiên bản gần đây Python, 'functools.wraps' làm điều gì đó để làm cho 'inspect.getargspec' và' kiểm tra .signature' báo cáo chữ ký của hàm được bọc, nhưng nó không thay đổi chữ ký thực của trình bao bọc. Thư viện bên thứ ba ['decorator'] (https://pypi.python.org/pypi/decorator) cung cấp chức năng trang trí bảo quản chữ ký thực thông qua các phương tiện mà tôi chưa bao giờ nhìn sâu vào, có thể liên quan đến một số thứ như viết lại bytecode. Tôi chưa bao giờ sử dụng nó. – user2357112

+0

Có thể kiểm tra nội dung nào đó như http://stackoverflow.com/questions/3729378/how-can-i-programmatically-change-the-argspec-of-a-function-in-a-python-decorato – Nf4r

Trả lời

2

Như đã đề cập trong ý kiến, bạn có thể sử dụng các mô-đun decorator hoặc bạn có thể sử dụng eval quyền hạn ác để tạo một hàm lambda có chữ ký chính xác:

import inspect 

def identity_decorator(wrapped): 
    argspec = inspect.getargspec(wrapped) 
    args = inspect.formatargspec(*argspec) 

    def wrapper(*args, **kwargs): 

     return wrapped(*args, **kwargs) 

    func = eval('lambda %s: wrapper%s' % (args.strip('()'), args), locals()) 

    return func 

@identity_decorator 
def foo(a): 
    pass 

Đây là kinda hackish, nhưng nó bảo đối số chức năng:

>>> inspect.getargspec(foo) 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None) 
1

AFAIK, nó có thể chỉ từ Python 3.3 với Signature đối tượng:

def identity_decorator(wrapped): 
    def wrapper(*args, **kwargs): 
     return wrapped(*args, **kwargs) 
    wrapper.__signature__ = inspect.signature(wrapped) # the magic is here! 
    return wrapper 

Sau đó, bạn có thể làm:

@identity_decorator 
def foo(a): 
    pass 

và cuối cùng là:

>>> inspect.getargspec(foo) 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None) 
Các vấn đề liên quan