[python专题笔记]修饰器学习

修饰器

修饰器介绍

Python的修饰器(decorator) 是一个非常强大的功能,一种优秀的设计模式(装饰器模式),将重复的内容抽象出来,赋予一个函数其他的功能,但又不去改变函数自身。使得代码极其简洁,易于维护。但其本质上还是一个语法糖

装饰器模式简介

装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型
的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有
的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

优点: 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点: 多层装饰比较复杂。
使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。
注意事项: 可代替继承。

修饰器解决现实问题

在实际的项目中,经常会遇到需要在原有项目上加一些功能,但是这些功能可能很快被删除掉,如何实现这种要求呢?如下例子:

def function():
    print("hello word !")
  1. 如果我想打印上述函数的执行时间,该如何做?
def function():
    start_time = time()
    print("hello word !")
    end_time = time()
    print(end_time - start_time)
  1. 如上的操作,修改了原始函数
  2. 假如函数很复杂,那么我想快速增加功能和删除功能,对原始函数修改较大,特别是反复删除和增加修改困难
  3. 使函数代码越来越大,不简洁
  4. 这种在原有函数里面加代码,也不符合开闭原则

修饰器实现例子

@print_run_time
def function():
    print("hello word !")

修饰器的实现

函数是对象的理解

在Python中,万物皆对象。(Everything in Python is an object.),当你定义一个函数的时候,你就得到了一个函数对象,这个对象的引用就是函数名。通过函数名,你可以做如下事情:

  1. 调用函数
  2. 将函数赋值给其它变量
  3. 把它当成参数传给其它函数
  4. 可以在函数内定义一个函数,并做为返回值返回
# 定义一个加法函数
def add(a, b):
    return a + b
 
# 1. 调用函数
sum1 = add(1, 2)

# 2. 把函数赋值给其它变量
sum_of_two_num = add
# 通过其它变量调用add
sum2 = sum_of_two_num(2, 3)

# 3. 把它当成参数传给其它函数
def function_1(str_content):
    return str_content + "function_1"

str_list = ["xiaoshu_", "LSK_"]
#map map(function_1, str_list) 就是 对 str_list 中的每个元素x调用 function_1(x)
print(list(map(function_1, str_list)))


# 4. 可以在函数内定义一个函数,并做为返回值返回
def test1():
    print("======================== test1 =========>")
    def test2(input_data):
        if type(input_data) != str:
            print("非字符串 !")
        else:
            print("字符串 !")
    return test2

t = test1()
print(t)

t("STR")
t(1)

为函数增加功能(修饰一下函数)

我写了一个加法计算的函数,现在我需增加一个功能,增加一个类型判断,但是这个功能又不想嵌入加法函数内,因为我想使得代码极其简洁,易于维护。代码如下:

def test1(function):
    print("======================== test1 =========>")
    def test2(input_1, input_2):
        if type(input_1) == int and type(input_2) == int:
            print("输入类型正确")
            return function(input_1, input_2)
        else:
            print("输入类型错误")
            return False
    return test2

def add(x, y):
    return x + y

new_add = test1(add)
print(new_add)
print(new_add(1, 2))

问题: 这个写法,要实现函数新增功能的时候,需要在调用的时候多写步骤,假如在多个地方调用,那么修改起来复杂

正确且简单写法

def test1(function):
    print("======================== test1 =========>")
    def test2(input_1, input_2):
        if type(input_1) == int and type(input_2) == int:
            print("输入类型正确")
            return function(input_1, input_2)
        else:
            print("输入类型错误")
            return False
    return test2

@test1
def add(x, y):
    return x + y

print(add(1, 2))

如下代码,可以想象是一个函数的帽子,在执行函数之前,把函数作为参数,传入帽子计算完毕后,再执行本函数

@test1

修饰器几种修饰场景

一 用函数修饰函数

#一 用函数修饰函数
def test1(function):
    print("======================== test1 =========>")
    def test2(input_1, input_2):
        if type(input_1) == int and type(input_2) == int:
            print("输入类型正确")
            return function(input_1, input_2)
        else:
            print("输入类型错误")
            return False
    return test2

@test1
def add(x, y):
    return x + y

print(add(1, 2))

二 用函数修饰类

# 二、用函数修饰类
#!/usr/bin/python3

def decorate_class(aClass):
    def call(*args, **kwargs):
        print('you have create a %s class, its name is %s.' % (aClass.__name__, args[0]))
        return aClass(*args, **kwargs)
    return call

@decorate_class
class People():
    def __init__(self, name):
        self.name = name


    def print(self):
        print('My name is %s.' % (self.name))

a = People('Tom')
a.print()


b = People('Jerry')
b.print()

三 用函数修饰类方法

# 三、用函数修饰类方法
#!/usr/bin/python3

def decorate_method(func):
    def call(*args, **kwargs):
        print('you have called %s().' % (func.__name__))
        func(*args, **kwargs)
    return call

class aClass():
    def __init__(self, name):
        self.name = name
    @decorate_method
    def print(self):
        print('My name is %s.' % (self.name))
a = aClass('Jerry')
a.print()

四 用类修饰函数

# 四、用类修饰函数
#!/usr/bin/python3
class decorate_func():
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('youhave called %s().' % (self.func.__name__))
        self.func(*args, **kwargs)

@decorate_func
def func(name):
    print('My name is %s.' % (name))

func('Bob')

五 用类修饰类

# 五、用类修饰类
#!/usr/bin/python3

class decorate_class():
    def __init__(self, aClass):
        self.aClass = aClass
    def __call__(self, *args, **kwargs):
        print('You have created a %s class.' % (self.aClass.__name__))
        return self.aClass(*args, **kwargs)

@decorate_class
class People():
    def __init__(self, name):
        self.name = name
    def print(self):
        print('My name is %s .' % (self.name))

a = People('Tom')

六 匿名函数作为函数修饰器

# 六、匿名函数作为函数修饰器
#!/usr/bin/python3

def attrsetter(attr, value):
    """ Return a function that sets ``attr`` on its argument and returns it. """
    return lambda method: setattr(method, attr, value) or method

def depends(*args):
    if args and callable(args[0]):
        args = args[0]
    elif any('id' in arg.split('.') for arg in args):
        raise NotImplementedError("Compute method cannot depend on field 'id'.")
    return attrsetter('_depends', args)

class People():
    def __init__(self, name):
        self.name = name
    # 这里用的是函数修饰器,但不是depends函数,而是depends函数执行完之后返回的匿名函数作为函数装饰器
    @depends('test')
    def print(self):
        print('My name is %s .' % (self.name, ))

a = People('Tom')
a.print()
print(a.print.__dict__)

参考

https://www.cnblogs.com/willsdu/p/16422647.html

https://www.cnblogs.com/watermeloncode/p/16531534.html

https://zhuanlan.zhihu.com/p/160979609

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值