目录

Python中的装饰器

高阶函数的举例

装饰器

带参数的装饰器

Python中的链接装饰器


Python中的装饰器

Python有一个有趣的功能,称为装饰器,可以向现有代码添加功能。

这也称为元编程,因为程序的一部分试图在编译时修改程序的另一部分。

Python中的所有内容(是!甚至是类)都是对象。我们定义的名称只是绑定到这些对象的标识符。函数也不例外,它们也是对象(带有属性)。

"""
first和second指代相同的功能对象。可以将函数作为参数传递给另一个函数。将其他函数作为参数的此类函数也称为高阶函数
"""
def first(msg):
    print(msg)

first("Hello") # Hello

second = first  # second 是高阶函数
second("Hello") # Hello

高阶函数的举例

def inc(x):
    return x + 1


def dec(x):
    return x - 1


def operate(func, x):
    result = func(x)
    return result

# is_returned()是一个嵌套函数,它在每次调用时都定义并返回is_called()
def is_called():
    print('111')
    def is_returned():
        print("Hello")
    return is_returned


if __name__ == '__main__':
    # 可以将函数作为参数传递给另一个函数
    o1 = operate(inc, 3)
    o2 = operate(dec, 3)
    print(o1) # 4
    print(o2) # 2

    # 一个函数可以返回另一个函数
    new1 = is_called() # 111
    print(new1) # <function is_called.<locals>.is_returned at 0x00000248F32738B8>
    new2 = new1() # Hello
    print(new2) # None
    # 111
    # <function is_called.<locals>.is_returned at 0x00000248F32738B8>
    # Hello
    # None

函数和方法是可以被调用。基本上,装饰器接受一个函数,添加一些功能并返回它。

装饰器

# 函数和方法被称为可调用的,因为它们可以被调用
# 基本上,装饰器接受一个函数,添加一些功能并返回它

def make_pretty(func):
    def inner():
        print("I got decorated")
        func()
    return inner


def ordinary():
    print("I am ordinary")


if __name__ == '__main__':
    ordinary() # I am ordinary

    pretty = make_pretty(ordinary)  # 将一个函数作为参数传给新的函数
    pretty() # make_pretty返回一个函数,()实例化它
             # I got decorated
             # I am ordinary

# 这里make_pretty()是一个装饰器
# 函数ordinary()得到了装饰,并返回的新的函数pretty

# 我们可以看到装饰器函数在原始函数中添加了一些新功能。print("I got decorated")
# 这类似于包装礼物。装饰器充当包装器。装饰的对象(内部实际礼物)的性质不会改变。但是现在,它看起来很漂亮(因为它已经被装饰了)。

# 通常,我们装饰一个函数并将其重新分配为
# ordinary = make_pretty(ordinary)
# This is a common construct and for this reason, Python has a syntax to simplify this.

带参数的装饰器

def divide(a, b):
    return a/b

def smart_divide(func):
    def inner(a, b):
        print("I am going to divide", a, "and", b)
        if b == 0:
            print("Whoops! cannot divide")
            return

        return func(a, b)
    return inner


@smart_divide
def divide(a, b):
    print(a/b)


if __name__ == '__main__':
    # 调用divide()函数时,实际是调用smart_divide(divide(2,5)),实质是调用inner()函数
    divide(2, 5) # ==inner()
    divide(2,0)
    """
    I am going to divide 2 and 5
    0.4
    I am going to divide 2 and 0
    Whoops! cannot divide
    """

inner()装饰器内部的嵌套函数的参数与其装饰的函数的参数相同。考虑到这一点,现在我们可以使通用装饰器可以使用任意数量的参数。

在Python中,这种魔术是通过完成的function(*args, **kwargs)。这样,args将成为位置参数的元组,kwargs并将成为关键字参数的字典。这样的装饰器的一个例子是:

def works_for_all(func):
    def inner(*args, **kwargs):
        print("I can decorate any function")
        return func(*args, **kwargs)
    return inner

Python中的链接装饰器

这就是说,一个功能可以用不同(或相同)的装饰器多次装饰。我们只需将装饰器放置在所需功能之上。

def star(func):
    def inner(*args, **kwargs):
        print("*" * 30)
        func(*args, **kwargs)
        print("*" * 30)
    return inner


def percent(func):
    def inner(*args, **kwargs):
        print("%" * 30)
        func(*args, **kwargs)
        print("%" * 30)
    return inner


@star
@percent
def printer(msg):
    print(msg)

# ==
# printer = star(percent(printer))


if __name__ == '__main__':
    printer("Hello")