Skip to content

面向对象、闭包、装饰器

一、面向对象 - super关键字

python
# super(更适合单继承的场景)
# 语法:super(类型,实例对象)
# 作用:找到当前类的下一级(父类)mro继承关系
# super一般不会在类外部使用,在类内部使用时,可以不传递参数(找的是父类)

1. 类的属性和方法的继承

python
class A():
    name = 'zs'
    def fn():
        print('fn')
class B(A):
    pass

直接继承了A的name和fn

2. 类的动态属性和动态方法的继承

python
# 1.Father(需要继承的类).init
# 2.super.init

class A():
    def __init__(self):
        self.name = 'zs'
        self.age = 18
        
a = A()
a会拥有name和age属性
class B(A):
    def __init__(self):
        # 继承的属性
        A.__init__(self)
        # 自己再添加额外的属性
        self.money = 100000

3. 混合继承

混合继承 = 类的属性/方法 + 动态属性/方法

4. 内置装饰器

类的方法默认叫做构造方法 - def fn(self):

​ @staticmethod:给类的方法进行装饰,将类的方法改造为静态方法 - def fn():

python
# 如果类里面没有使用self,改造成@staticmethod
# 单例模式使用类的属性(方法),使用类名.属性(方法名)

​ @classmethod:给类的方法进行装饰,将类的方法改造为类方法 - def fn(cls):

python
# 装饰的方法,第一个参数是cls,cls表示类本身
# 装饰的方法一般给静态类(单例)使用

二、垃圾回收机制

  1. 标记清除法:如果一个变量不可访达,那么这个变量对应的内存就可以被回收
  2. 引用计数法
  3. 分代回收

三、闭包

  • 闭包核心:绕过垃圾回收机制的一种高级编程思想
  • 闭包三要素:
    1. 外部函数函数嵌套内部函数(有嵌套)
    2. 函数内部引用外部函数的变量(有引用) 关键字nonlocal
    3. 返回内部函数名(不能有括号)(有返回)
python
# 使用闭包实现累计计数
def outer_fn():
    count = 0

    # 有嵌套
    def inner_fn():
        # 有引用
        nonlocal count
        count += 1
        print(f'当前的count为{count}')

    # 有返回
    return inner_fn


# 接受返回值
fn = outer_fn()
# 调用
fn()

四、装饰器的实现

1.有嵌套

2.有引用

3.有返回(返回的东西叫闭包)

4.有实现内容

五、装饰器的分类

1. 无参无返回值

python
import time
# 定义统计用时装饰器
def check_time(fn):
    # 有嵌套
    def inner_fn():
        # 函数执行前时间
        start = time.time()
        # 有调用(外部函数形参)
        fn()
        # 函数执行后时间
        end = time.time()
        # 打印执行时间按
        print('函数执行时间:%f' % (end - start))
    # 返回内部函数名
    return inner_fn
# 手搓
def work():
    a = 1
    b = 2
    print(a + b)
    time.sleep(2)
1.通过check装饰work,构造一个新的fn
new_work = check_time(work)
2.新的fn调用才能实现效果
new_work()
# 语法糖
@check_time
def work():
    a = 1
    b = 2
    print(a + b)
    time.sleep(2)
# 调用
work()

2. 有参无返回值

核心:有参数的时候,只需要用inner_fn接收这个参数就行

python
import time
# 定义统计用时装饰器
def check_time(fn):
    # 有嵌套
    def inner_fn(a, b):
        # 函数执行前时间
        start = time.time()
        # 有调用(外部函数形参)
        fn(a, b)
        # 函数执行后时间
        end = time.time()
        # 打印执行时间按
        print('函数执行时间:%f' % (end - start))
    # 返回内部函数名
    return inner_fn
# 手搓
def work(a, b):
    print(a + b)
    time.sleep(2)
new_work = check_time(work)
# 调用
new_work(1, 2)

# 语法糖
@check_time
def work(a, b):
    print(a + b)
    time.sleep(2)
# 调用
work(1, 2)

3. 无参有返回值

核心:inner_fn里面加return

python
import time
# 定义统计用时装饰器
def check_time(fn):
    # 有嵌套
    def inner_fn():
        # 函数执行前时间
        start = time.time()
        # 有调用(外部函数形参)
        res = fn()
        # 函数执行后时间
        end = time.time()
        # 打印执行时间按
        print('函数执行时间:%f' % (end - start))
        return res
    # 返回内部函数名
    return inner_fn
# 手搓
def work():
    a = 1
    b = 2
    time.sleep(2)
    return (a + b)
new_work = check_time(work)
# 调用
print(new_work())
# 语法糖
@check_time
def work():
    a = 1
    b = 2
    time.sleep(2)
    return a + b
# 调用
print(work())

4.有参有返回值

python
import time
# 定义统计用时装饰器
def check_time(fn):
    # 有嵌套
    def inner_fn(a, b):
        # 函数执行前时间
        start = time.time()
        # 有调用(外部函数形参)
        res = fn(a, b)
        # 函数执行后时间
        end = time.time()
        # 打印执行时间按
        print('函数执行时间:%f' % (end - start))
        return res
    # 返回内部函数名
    return inner_fn
# 手搓
def work(a, b):
    time.sleep(2)
    return a + b
new_work = check_time(work)
# 调用
print(new_work(1,2))
# 语法糖
@check_time
def work(a, b):
    time.sleep(2)
    return a + b
# 调用
print(work(1, 2))

5. 通用装饰器

python
# 通用装饰器模板
def check_time(fn):
    # 有嵌套
    def inner_fn(*args, **kwargs):
        # -------------------------装饰器功能【先执行装饰器功能】
        print('功能')
        # -------------------------装饰器功能【先执行装饰器功能】
        # 有调用(外部函数形参)
        res = fn(*args, **kwargs)
        # -------------------------装饰器功能【后执行装饰器功能】
        print('功能')
        # -------------------------装饰器功能【后执行装饰器功能】
        return res

    # 返回内部函数名
    return inner_fn

@check_time
def work(*args, **kwargs):
    num_sum = 0
    # 求元组args的和
    for i in args:
        num_sum += i
    # 求字典kwargs的和
    for i in kwargs:
        num_sum += kwargs[i]
    print(f'和为{num_sum}')
    
# 补充:
# 原则:关键字不定长写在位置不定长后面
# 原则:位置参数写在默认值参数前面

六、装饰器的其他使用

1. 多装饰器的使用

效果:装饰器执行顺序按照从上往下逐个执行

原理:装饰的顺序从下到上,把装饰器加函数当作一个新函数

python
# 登录
def login(fn):
    def inner_fn(*args, **kwargs):
        print('请先登录')
        res = fn(*args, **kwargs)
        return res
    return inner_fn
# 评论
def comment(fn):
    def inner_fn(*args, **kwargs):
        print('发布评论')
        res = fn(*args, **kwargs)
        return res
    return inner_fn
# 点赞
@login
@comment
def like():
    print('点赞')

2. 装饰器的参数

装饰器如果有参数,需要在原来的装饰器的基础上再包裹一层进行接收

python
def flag(flag):
    def param_calc(fn):
        def inner_fn(*arg, **kwargs):
            res = fn(*arg, **kwargs)
            if flag == '+':
                print('装饰器加法执行完成~')
            else:
                print('装饰器减法执行完成~')
            return res
        return inner_fn
    return param_calc
@flag('+')
def calc1(a, b):
    print(a + b)
@flag('-')
def calc2(a, b):
    print(a - b)
# 调用
calc1(1, 2)
calc2(1, 2)