Skip to main content
 首页 » 编程设计

python之关于如何通过 Python 装饰器传递参数的困惑

2025年05月04日12lori

TL;DR:如果函数装饰器没有具体指定参数,那么装饰函数是否具有与未装饰函数相同的参数要求(在参数计数和参数名称方面)?

我有一个 web 应用程序的 Controller ,它处理所有购物车 ajax 调用。在每次调用开始时,它都会初始化一个对象,该对象处理购物车功能的实际逻辑。 (这可能不是最有效的方法,但我的问题与实际的购物车位没有任何关系。)

代码如下所示:

from webapp import request 
 
from shopping_cart import Cart 
from decorators import decorator 
 
@decorator 
def init_cart(f, *args, **kwargs): 
    shopping_cart = Cart() 
    return f(shopping_cart = cart) 
 
@init_cart 
def add_item(shopping_cart = None): 
    shopping_cart.add(request.params) 
 
@init_cart 
def remove_item(shopping_cart = None): 
    shopping_cart.remove(request.params) 

等等。

该代码存在于一个集中式模块中,由多个应用程序导入和调用。各个应用程序中的代码如下所示:

from sharedlib.controllers import cart 
from app.base import * 
 
class CartController(BaseController): 
 
    def index(self, url = None): 
        set_content_type('text/javascript') 
        controller_method = getattr(cart, url) 
        if controller_method: 
            return controller_method() 
        else: 
            abort(404) 

我的问题如下:

如果我希望 init_cart 装饰器将它接收到的参数传递给被调用的 Controller 方法,除了传递 cart 模块之外,我会尝试:

@decorator 
def init_cart(f, *args, **kwargs): 
    shopping_cart = Cart() 
    kwargs['shopping_cart'] = cart 
    return f(*args, **kwargs) 
 
@init_cart 
def add_item(shopping_cart = None): 
    shopping_cart.add(request.params) 

但是我抛出了一个异常,TypeError: add_item() got multiple values for keyword argument 'shopping_cart'

我不完全理解这种行为:kwargs 肯定只有一个键/值对用于“shopping_cart”。

此外,如果我尝试这样做:

@decorator 
def init_cart(f, *args, **kwargs): 
    shopping_cart = Cart() 
    return f(cart) 
 
@init_cart 
def add_item(shopping_cart = None): 
    shopping_cart.add(request.params) 

我收到错误 TypeError: add_item() takes exactly 1 argument (0 given)

我假设我不知道装饰器在接收和传递参数时的行为方式——我假设如果 init_cart 使用 (*args, **kwargs ) 然后它修饰的函数可以用任何参数集调用,或者没有参数集。事实并非如此。

此外,在前面的示例中,该方法如何为 shopping_cart 参数接收多个值?

请您参考如下方法:

def this_is_a_decorator(fn): 
    def decorated_fn(*args,**kwargs): 
        result = fn(*args,**kwargs) #notice we are calling the original function 
        return "%s decorated"%result 
    return decorated_fn 
 
@this_is_a_decorator 
def reverse_string(msg=""): 
    return msg[::-1] 
 
print reverse_string("Hello!") 

为你的装饰器

def init_cart(fn): 
    def decorated_fn(*args,**kwargs): 
        cart = Cart() 
        fn(cart) 
        return cart 
    return decorated_fn 
 
@init_cart 
def add_item(shopping_cart=None): 
     shopping_cart.add(request.params)