2011-07-05 28 views
5

Đối với trang trí tôi viết, tôi muốn thao tác một tham số được đặt tên cụ thể của hàm. Hãy xem xét các trang trí sau:Làm cách nào tôi có thể xử lý đối số vị trí dưới dạng đối số từ khóa trong Python 2

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
    return func_caller 
return func_decorator 

Ứng dụng trên chức năng tiếp theo:

@square_param('dividend') 
def quotient(divisor=1,dividend=0): 
    return dividend/divisor 

Điều này sẽ có tác dụng nếu cổ tức được gọi là một cuộc tranh luận từ khóa ví dụ:

>>> quotient(dividend=2) 
4 

Tuy nhiên, khi đưa ra là một lập luận vị trí điều này sẽ thất bại.

>>> quotient(3,4) 
TypeError: quotient() got multiple values for keyword argument 'dividend' 

Với Python 3 tôi có thể giải quyết việc này bằng cách buộc các tham số để được always given as a keyword:

@square_param('dividend') 
def quotient(divisor=1,*,dividend=0): 
    return dividend/divisor 

nhưng tôi muốn hỗ trợ Python 2 và tôi cũng muốn đặt các hạn chế càng ít về chức năng .

Có cách nào để tôi có thể khắc phục hành vi này trong trang trí của mình không?

+3

Kiểm tra các mô-đun kiểm tra. Nó có thể có những gì bạn cần cho việc này. Có một cái nhìn tại getargspec. – Dirk

Trả lời

3

Thứ nhất, trang trí square_param của bạn không hoạt động vì nó không trả về các chức năng. Cần phải:

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
     return func_caller 
    return func_decorator 

Bây giờ tôi đã nhận lời khuyên của Dirk và xem mô-đun inspect. Bạn có thể làm điều đó bằng cách kiểm tra đầu tiên nếu tham số là một trong các đối số vị trí của hàm, và thứ hai nếu đối số vị trí đã được chỉ định, và sau đó sửa đổi vị trí đối số đó. Bạn cũng cần phải chắc chắn rằng bạn chỉ sửa đổi kwargs nếu tham số được cung cấp như một đối số từ khóa.

import inspect 

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      funparams = inspect.getargspec(func).args 
      if param in funparams: 
       i = funparams.index(param) 
       if len(args) > i: 
        args = list(args) # Make mutable 
        args[i] = args[i] * args[i] 
      if param in kwargs: 
       kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
     return func_caller 
    return func_decorator 
+0

Cảm ơn, đây chính xác là những gì tôi đang tìm kiếm! Về sự trở lại của các hàm, đó thực sự là một lỗi nhỏ ngu ngốc được thực hiện trong ví dụ này. –

2

ngay cả khi không sử dụng Kiểm tra chúng tôi có thể nhận được chức năng params

>>> func = lambda x, y, args: (x, y, {}) 
>>> func.func_code.co_argcount 
3 
>>> func.func_code.co_varnames 
('x', 'y', 'args') 
+0

Cảm ơn! Có thể bạn có thể thêm một liên kết nơi các thành viên func_code được tài liệu? Tôi không thể tìm thấy điều đó. –

+0

Bạn được chào đón! "func_code là đối tượng mã thể hiện phần thân hàm được biên dịch." Bạn có thể tham khảo phần "Loại có thể gọi" trên [link] (http://docs.python.org/reference/datamodel.html) để biết thêm chi tiết. – Yajushi

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