【问题标题】:Use decorator to change argument of a decorated function使用装饰器更改装饰函数的参数
【发布时间】:2022-01-04 03:32:59
【问题描述】:

背景

我想对相同的数据执行不同的方法。不同的方法是原始方法的变体,只是param:p3 的参数不同。

# This is original method
def method(p1,p2,p3,data):
    return data + p1 + p2 + p3
method(p1=1, p2=2, p3=3, data=10)

16

# By changing param:p3, I can define 3 methods based on original method.
# but it seems stupid and very unclear...
def method1(*args, **kw):
    return method(*args, **kw, p3 = 1)
def method2(*args, **kw):
    return method(*args, **kw, p3 = 2)
def method3(*args, **kw):
    return method(*args, **kw, p3 = 3)
method1(p1=1,p2=2,data =10),\
method2(p1=1,p2=3, data =100)

(14,106)

问题

是否有任何装饰器可以将我原来的 method 修改为任何变体,例如 method1

# After decorated, method equals to method1
@decorator(p3 = 1)
def method(p1,p2,p3,data):
    return data + p1 + p2 + p3

# After decorated, method equals to method2
@decorator(p3 = 2)
def method(p1,p2,p3,data):
    return data + p1 + p2 + p3

或者,我不应该使用装饰器来满足我的需求,或者使用一个类来代替吗?

【问题讨论】:

  • 你看过functools.partial吗?
  • @rchome 谢谢!我会检查partial,看来可以满足我的需要

标签: python decorator


【解决方案1】:

要充实 rchome 的注释,您可以使用 functools.partial 如下:

>>> from functools import partial
>>> def method(p1,p2,p3,data):
...     return data + p1 + p2 + p3
>>> method1 = partial(method, p3=1)
>>> method2 = partial(method, p3=2)
>>> method3 = partial(method, p3=3)
>>> method1(p1=1,p2=2,data=10)
14
>>> method2(p1=1,p2=2,data=10)
15
>>> method3(p1=1,p2=2,data=10)
16

【讨论】:

    【解决方案2】:

    我们可以使用装饰器来做同样的事情,如下所示:

    # this is a decorator factory
    def de_fac(**out_kw):
        def my_decorator(f):
            def wrapper(*args, **kw):
                print('inside function arguments:',{*args})
                print('inside function keywords:',{**kw})
                print("outside decorator factory\'s arguments:", {**out_kw})
                # override {**kw} with {**out_kw}
                return f(*args, **{**kw, **out_kw})
            return wrapper
        return my_decorator
    
    
    @de_fac(p3=1)
    def method_to_be_dec(p1,p2,p3,data):
        return data + p1 + p2 + p3
    
    # it's same
    method_to_be_dec(p1=1, p2=2, data=10), method1(p1=1, p2=2, data=10)
    

    函数内部参数:set()
    函数内部关键字:{'p1': 1, 'p2': 2, 'data': 10}
    外部装饰器工厂的参数:{'p3': 1}
    (14, 14)

    【讨论】:

    • 在上面的代码中,我们使用装饰器来覆盖函数参数。我还有一个问题:我们可以使用装饰器来覆盖函数体吗?
    • 以这种方式使用装饰器有什么意义?你可以把 p3=1 放在函数体内。如果你想覆盖函数体,只需编写不同的函数体而不是添加装饰器。
    • 我同意 functools.partial 在这篇文章中是首选。我刚刚学习了一些关于装饰器的知识,我想用装饰器尝试任何东西,以确定在什么情况下我们真正需要装饰器。
    猜你喜欢
    • 2022-08-15
    • 2018-05-24
    • 2014-07-21
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 2016-09-27
    • 1970-01-01
    相关资源
    最近更新 更多