一般来说,什么是Python编写装饰器的方法?[duplicate]

jljoyd4f  于 2023-03-16  发布在  Python
关注(0)|答案(2)|浏览(121)

此问题在此处已有答案

How do I make function decorators and chain them together?(20个答案)
9小时前关门了。
总的来说,我想知道如何用python编写一个简单的装饰器。
不过,提供一个具体的例子可能会有所帮助。
考虑以下函数:

def pow(base:float, exp:int):
    """
         +------------------------------------------+
         |                EXAMPLES                  |
         +------------------------------------------+
         | BASE | EXPONENT |       OUTPUT           |
         +------+----------+------------------------+
         |    2 |        5 | 2^5      |          32 |
         |  2.5 |        7 | 2.5^7    | 610.3515625 |
         |   10 |        3 | 10^3     |        1000 |
         |  0.1 |        5 | 0.1^5    |     0.00001 |
         |    7 |        0 | 7^0      |           1 |
         +------+----------+----------+-------------+
    """
    base = float(base)
    # convert `exp` to string to avoid flooring, or truncating, floats
    exp  = int(str(exp))
    if exp > 0:
        return base * pow(base, exp-1)
    else: # exp == 2
        return 1

在原始实现中,以下函数调用将导致错误:

raw_numbers = [0, 0]
raw_numbers[0] = input("Type a base on the command line and press enter")  
raw_numbers[1] = input("Type an exponent (power) on the command line and press enter")

numbers = [float(num.strip()) for num in raw_numbers]

# As an example, maybe numbers == [4.5, 6]

result = pow(numbers)

print(result)

假设我们想修饰pow函数,使下面两个调用都有效:

  1. result = pow(numbers),其中numbers是对列表对象[4.5, 6]的引用
  2. result = pow(4.5, 6)
    我们想使用一个名为类似于flatten_args的装饰器...
@flatten_args
def pow(*args):
   pass

我们如何编写这样一个装饰器呢?
另外,当我们修饰一个可调用对象时,我们如何保存文档字符串?

print(pow.__doc__)
xkrw2x1b

xkrw2x1b1#

编写Python装饰器最简单的方法是作为一个返回函数的函数。

def flatten_args(func):
    '''
    Decorator to allow multi-argument functions to be called with arguments in list/tuple.
    '''
    # Helper function to implement the decorator behavior.
    def wrapped_func(*args):
        if len(args) == 1:
            return func(*args[0])
        else:
            return func(*args)
    # Make help() behave
    wrapped_func.__name__ = func.__name__
    wrapped_func.__doc__ = func.__doc__
    return wrapped_func
w46czmvw

w46czmvw2#

下面是一个装饰器的例子,它是一半的Python或更多:

class print_calling_args:

    def __new__(cls, kallable):
        instance = super().__new__(cls)
        instance = functools.update_wrapper(instance, kallable)
        return instance

    def __init__(self, kallable):
        self._kallable = kallable
        self._file     = sys.stdout

    def __call__(self, *args, **kwargs):
        print("__init__(" + ", ".join(str(x) for x in [self, *args]) + ")", file=self._file)
        return self._kallable(*args, **kwargs)

下面,我们装饰一个pow函数。
我们可以直接写10**3,表示10的三次方,但是这是一个很好的简单的例子,我们可以修饰它。

@decorator
def pow(base:float, exp:int):
    """
         +------------------------------------------+
         |                EXAMPLES                  |
         +------------------------------------------+
         | BASE | EXPONENT |       OUTPUT           |
         +------+----------+------------------------+
         |    2 |        5 | 2^5      |          32 |
         |  2.5 |        7 | 2.5^7    | 610.3515625 |
         |   10 |        3 | 10^3     |        1000 |
         |  0.1 |        5 | 0.1^5    |     0.00001 |
         |    7 |        0 | 7^0      |           1 |
         +------+----------+----------+-------------+
    """
    base = float(base)
    # convert `exp` to string to avoid flooring, or truncating, floats
    exp  = int(str(exp))
    if exp > 0:
        return base * pow(base, exp-1)
    else: # exp == 2
        return 1

下面,我们看到修饰的pow函数被一些简单的输入调用:

result1 = pow(2, 5)
result2 = pow([8.1, 0])
print("pow(2, 5)"    , " == ", result1)
print("pow([8.1, 0])", " == ", result2)

注意,文档字符串仍然可以透过 Package 器透明地看到:

print(pow.__doc__)

相关问题