python装饰器

1.闭包

1.1定义

在函数内部再定义一个函数并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包

def hi(name="yasoob"):
    print("hi")

    def greet():
        return "greet"

    def welcome():
        return "welcome"

    print(greet())
    print(welcome())


hi()
# 输出
# hi
# greet
# welcome

1.2从函数中返回函数

def hi(name="yasoob"):
    def greet():
        return "greet"

    def welcome():
        return "welcome"

    if name == "yasoob":
        return greet
    else:
        return welcome


a = hi()
print(a) #outputs: <function greet at 0x7f2143c01500>
print(a()) #outputs: greet

1.3将函数作为参数传递给另一个函数

def hi():
    return "hi yasoob!"


def doSomethingBeforeHi(func):
    print("before executing hi()")
    print(func())


doSomethingBeforeHi(hi)
# outputs: before executing hi()
#          hi yasoob!

2.装饰器

2.1装饰函数的装饰器

2.1.1函数装饰器
1.不带参数的
from functools import wraps


def decorator1(a_func):
    def my_wrap():
        print("decorator1_1")
        a_func()
        print("decorator1_2")

    return my_wrap


def decorator2(a_func):
    @wraps(a_func)
    def my_wrap():
        print("decorator2_1")
        a_func()
        print("decorator2_2")

    return my_wrap


def decorator3(a_func):
    @wraps(a_func)
    def my_wrap():
        print("decorator3_1")
        return a_func()

    print("decorator3_2")
    return my_wrap


def decorator4(a_func):
    @wraps(a_func)
    def my_wrap(*args, **kwargs):
        print("decorator4_1")
        return a_func(*args, **kwargs)

    return my_wrap


def a():
    print("a")


@decorator1
def b():
    print("b")


@decorator2
def c():
    print("c")


@decorator3
def d():
    return "d"


@decorator4
def e(e_str):
    return e_str


if __name__ == '__main__':
    # 1.将函数作为参数进行传递装饰
    a = decorator1(a)
    a()
    # output
    # decorator1
    # a
    # decorator1

    # 2.使用@进行装饰
    b()
    # decorator2
    # b
    # decorator2

    # 3.重写函数名字和注释文档
    print(b.__name__)  # output:my_wrap
    print(c.__name__)  # output:c

    # 4.被装饰的函数有返回值:则不能不对其返回后的值进行装饰
    print(d())
    # decorator3_2
    # decorator3_1
    # d
    # 5.被装饰的函数带有参数
    print(e("e_str"))

注意:

1.@new_decorator等价与b = new_decorator(b)

2.functools.wraps重写函数名字和注释文档参数列表等等的功能

3.被装饰的函数有返回值,则不能对其返回后的值进行装饰

4.被装饰的函数带有参数

2.带参数的
from functools import wraps


def say_hello(country):
    def wrapper(func):
        @wraps(func)
        def deco(*args, **kwargs):
            if country == "china":
                print("你好!")
            elif country == "america":
                print('hello')
            else:
                return "decorate error"
            return func(*args, **kwargs)

        return deco

    return wrapper


# 小明,中国人
@say_hello("china")
def xiaoming():
    pass


# jack,美国人
@say_hello("america")
def jack():
    pass


if __name__ == '__main__':
    xiaoming()
    print("------------")
    jack()
2.1.2类装饰器
1.不带参数的

绝大多数装饰器都是基于函数和闭包实现的,但这并非制造装饰器的唯一方式 python 对某个对象是否能通过装饰器( @decorator)形式使用只有一个要求:decorator 必须是一个“可被调用(callable)的对象

class Logger(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f"[INFO]: the function {self.func.__name__}() is running...")
        return self.func(*args, **kwargs)


@Logger
def say(something):
    print(f"say {something}!")


if __name__ == '__main__':
    say("hello")
    # 输出
    # [INFO]: the function say() is running...
    # say hello!
2.带参数的
class Logger(object):
    def __init__(self, level="INFO"):
        self.level = level

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f"[{self.level}]: the function {func.__name__}() is running...")
            return func(*args, **kwargs)
        return wrapper


@Logger(level='WARNING')
def say(something):
    print(f"say {something}!")


if __name__ == '__main__':
    say("hello")
    # 输出
    # [WARNING]: the function say() is running...
    # say hello!
3.偏函数
import time
import functools


class DelayFunc:
    def __init__(self, duration, func):
        self.duration = duration
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Wait for {self.duration} seconds...')
        time.sleep(self.duration)
        return self.func(*args, **kwargs)

    def eager_call(self, *args, **kwargs):
        print('Call without delay')
        return self.func(*args, **kwargs)


def delay(duration):
    """
    装饰器:推迟某个函数的执行。
    同时提供 .eager_call 方法立即执行
    """
    # 此处为了避免定义额外函数,
    # 直接使用 functools.partial 帮助构造 DelayFunc 实例
    return functools.partial(DelayFunc, duration)


@delay(duration=2)
def add(a, b):
    return a + b


if __name__ == '__main__':
    print(add)  # output:<__main__.DelayFunc object at 0x0000026CBDF8A730>
    print(add(3, 5))
    # output
    # Wait for 2 seconds...
    # 8
    print(add.eager_call(3, 5))
    # output
    # Call without delay
    # 8
    print(add.func)# output <function add at 0x000001B85D5695E0>

2.2装饰类的装饰器

装饰器用在类上,并不是很常见,但只要熟悉装饰器的实现过程,就不难以实现对类的装饰

装饰器实现单例模式

instances = {}


def singleton(cls):
    def get_instance(*args, **kwargs):
        cls_name = cls.__name__
        print('===== 1 ====')
        if cls_name not in instances:
            print('===== 2 ====')
            instance = cls(*args, **kwargs)
            instances[cls_name] = instance
        return instances[cls_name]

    return get_instance


@singleton
class User:
    _instance = {}

    def __init__(self, name):
        print('===== 3 ====')
        self.name = name


if __name__ == '__main__':
    u1 = User("np1")
    # == == = 1 == ==
    # == == = 2 == ==
    # == == = 3 == ==
    u1.age = 20
    u2 = User("np2")
    # == == = 1 == ==
    print(u2.age)
    # 20
    print(u1 is u2)
    # True

参考

1.python中文指南 装饰器的六种写法
2.Python函数装饰器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值