从0开始python学习-17.装饰器

目录

1. 装饰器的基本逻辑

2. 常规格式的装饰器

3. 装饰器的语法糖格式

4. 带有参数的装饰器

5. 数据类装饰器@dataclass

6. @property装饰器

6.1 可以使用setter装饰器来将@property修饰后的方法变成变成具有读写功能的属性

6.2 可以使用deleter装饰器来删除指定属性


1. 装饰器的基本逻辑

1. 装饰器的概念:在不修改原来代码的情况下(函数原有的功能)的情况下,为装饰器的对象(原来的函数)增加新的功能或者添加限制条件以及帮助输出

2. 装饰器的常用的种类:函数的装饰器、类的装饰器

3. 主要的设计模式:开放封闭的原则(对外扩展开发,对内关闭修改)

4. 装饰器的定义: 装饰器本身是一个函数;装饰器的返回值是一个函数的引用(函数名字);装饰器只能必须一定是一个形参(形参:用来接收函数的引用(接收函数的名字))

5. 核心的使用原则:装饰器是给已有的函数增加额外的功能,本质上是一个闭包函数

6. 装饰器的功能特点:不修改被装饰的函数原代码;不修改已有函数的调用方式;给已有函数增加额外功能(通过函数外部的装饰器实现)

7. 解释器在执行代码的时候遇到装饰器先加载装饰器代码并执行

8. 装饰器本质上就是一个闭包函数,只不过传递过去的实参是被装饰函数的引用

2. 常规格式的装饰器

def a(b): # b为装饰器,必须是一个形参,用于接收函数的引用。b = c
    def inner():
        print("内部打印")
        b() # b函数的引用。等价于 b = c >> b() = c()
    return inner

def c():
    print('另一个打印')

d = a(c) # d = inner
d() # d() = inner()

3. 装饰器的语法糖格式

1. @装饰器的名字,通过语法糖完成对已有函数的装饰

2. 注意装饰器要写在被装饰的函数定义的上面

def a(b):
    def inner():
        print("内部打印")
        b()
    return inner

# 该语法等价于:变量名字 = 用于装饰的函数名称(被装饰的函数名称)
@a  # 等价于上面的 d = a(c)
def c():
    print('另一个打印')

c()

4. 带有参数的装饰器

1. 带有参数的装饰器就是使用被装饰器的函数的时候可以指定的传递参数

2. 使用带有参数的装饰器,其实就是给装饰器包裹了一个函数,使用该函数去接收装饰器需要使用的实参,返回的值是实际装饰器的名字,因为@符号需要配合装饰器实例使用

3. 装饰器的参数:可以使用python中任何的参数:位置参数,关键字参数,不定长参数,默认参数.......

# 给装饰器继续嵌套一个函数用来接收参数
def mark(flag):
    def b(c):
        def inner(num1,num2):
            if flag == '+':
                print("加法运算")
            elif flag == '-':
                print('减法运算')
            res = c(num1,num2)
            print(res)
            return res
        return inner
    return b

# 带参数的装饰器的使用,在装饰器的括号里面写上实参
@mark('+')
def add(num1,num2):
    res = num1+num2
    return res

@mark('-')
def sub(num1,num2):
    res = num1-num2
    return res


add(1, 2)
sub(3, 2)

5. 数据类装饰器@dataclass

1. 使用方法:先导入dataclasses模块,然后使用@dataclasses.dataclass
​​​​​​
2. 自动为类创建很多特殊方法包括init魔法方法,不需要手动的定义init直接使用 

3. 对类进行装饰的装饰器其实是实例属性的另外一种定义格式 

4. 该模块在Python3.7版本之后才能使用 5. 数据类定义的变量可以被类方法和实例方法使用
from dataclasses import dataclass

@dataclass
class A:
    name = '张三'
    age:int
    # 等价于
    # def __init__(self,age):
    #     self.name = '张三'
    #     self.age = age


    def a(self):
        print(f"姓名为{self.name}")
        print(f"年龄为{self.age}")

b = A(18)
b.a()

6. @property装饰器

1. @property装饰器,可以直接通过方法名来访问方法,不需要在方法名后添加括号

2. 语法格式为:
@property
def 方法名(self)
    代码块

3. 可以用来修饰方法,使方法作为属性使用。该属性是只读的,不可以被修改
class A:
    def __init__(self,age):
        self.age = age

    @property
    def b(self):
        return self.age

c = A(18)
# 可以直接通过方法名来访问方法b,不需要在后面加上括号b()
print('年龄是',c.b)
print('年龄是',c.b()) # TypeError: 'int' object is not callable,因为装饰器的使用后将方法作为了属性来使用了,所以不能使用c.b()

6.1 可以使用setter装饰器来将@property修饰后的方法变成变成具有读写功能的属性

语法格式:
@方法名.setter
def 方法名(self, value):
    代码块

@dataclass
class A:
    age:int

    @property
    def b(self):
        return self.age

    @b.setter
    # 这里被setter装饰的方法需要与用于装饰的方法名一致,便于使用
    def b(self,value):
        self.age = value

c = A(18)
print('原本设置年龄是',c.b)

c.b = 20 # 如果没有setter方法,修改属性值会报错:AttributeError: can't set attribute 'b'
print('修改后年龄是',c.b)

6.2 可以使用deleter装饰器来删除指定属性

语法格式为:

@方法名.deleter

def 方法名(self):

        代码块

@dataclass
class A:
    age:int

    @property
    def b(self):
        return self.age

    @b.setter
    # 这里被setter装饰的方法需要与用于装饰的方法名一致,便于使用
    def b(self,value):
        self.age = value

    # 这里理解为删除本质上是置为当前方法的值,使用后可以将之前的值便跟为该方法中设置的值
    @b.deleter
    def b(self):
        self.age = 10

c = A(18)
print('原本设置年龄是',c.b)

c.b = 20
print('修改后年龄是',c.b)

del c.b
print('删除后年龄是',c.b)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值