IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 详解2_装饰器-函数-python -> 正文阅读

[Python知识库]详解2_装饰器-函数-python

0、函数嵌套

变量名解析:LEGB原则

变量名查找:

  1. 首先从本地(L)查找;

  2. 本地没有找到,从上一层机构中的def或者lambda的本地作用域(E);

  3. 从全局作用域(G)中查找;

  4. 从内置的模块(B)中查找,第一个出现的地方查找;

nonlocal关键字:内部函数想要改变外部函数的变量,需要加nonlocal关键字,示例如下

def outer():
    a = 100

    def inner():
        nonlocal a
        b = 200
        a += b
        print('我是内部函数', a)

    inner()
    print(a)


outer()

1、闭包

1.1、概念

首先看一下维基上对闭包的解释:

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

1.2、条件

形成闭包的三个条件:

  1. 嵌套函数
  2. 内部函数引用外部函数的变量
  3. 返回内部函数
  • 简单示例如下

    '''
    求直线上的对应x的y值,方程式:
        y = a*x+b
    '''
    
    
    def outer(a, b):
    
        def inner(x):
            return a * x + b
    
        return inner
    
    
    line = outer(2, 1)
    print(line(1))
    

简单分析:通过断点查看

  • 此时line值为:<function outer..inner at 0x00000000031758B0>

1.3、闭包陷阱

先看一段代码:自己思考结果

def my_func(*args):
    fs = []
    for i in range(3):
        def func():
            return i * i

        fs.append(func)
    return fs


fs1, fs2, fs3 = my_func()
print(fs1())
print(fs2())
print(fs3())

结果会是0 1 4 吗?并不是 结果为 4 4 4,为什么呢?

  • 因为在函数my_func返回前其内部定义的函数并不是闭包函数,只是一个内部定义的函数。当然这个内部函数引用的父函数中定义的变量也不是自由变量,而只是当前block中的一个local variable。
  • 在内部定义的函数func实际执行前,对局部变量j的任何改变均会影响到函数func的运行结果

正确的写法:

def my_func(*args):
    fs = []
    for i in range(3):
        func = lambda _i=i: _i * _i
        fs.append(func)
    return fs


fs1, fs2, fs3 = my_func()
print(fs1())
print(fs2())
print(fs3())

2、装饰器

因为还没有学习面向对象,这里关于类装饰器相关的内容暂时不介绍,只讲解光宇函数装饰器内容。

下面我们通过模拟新房装修来认识下装饰器,你买了一座新房子(毛坯房),现在我们要对毛坯房进行装修。

开闭原则是编程中最基础、最重要的设计原则。

基本介绍:

  1. 一个软件实体如类,模块和函数应该对扩展开放(对于提供方来说),对修改关闭(对于使用方来说)。用抽象构建框架,用实现扩展细节。
  2. 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
  3. 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。

示例如下:

def decorator(func):
    def wrapper():
        func()
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('精装修房,可以入住啦~~~')

    return wrapper


@decorator
def house():
    print('毛坯房。。。')


house()

那么执行顺序是怎么样的呢?

def decorator(func):
    print('decorator start ...')

    def wrapper():
        print('wrapper start ...')
        func()
        print('wrapper end ...')

    print('decorator end ...')
    return wrapper


@decorator
def func():
    print('函数执行...')


# func()

执行结果:

decorator start …
decorator end …

执行顺序:加载decorator -> 加载原始func->执行decorator->func此时指向wrapper

  • 执行decorator时,把原始func作为实参传给decorator的形参

2.1、带参

还是以上面装修房子为例,我们是装修队的,需要知道房屋地址。

def decorator(func):
    def wrapper(address):
        func(address)
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('精装修房,可以入住啦~~~')

    return wrapper


@decorator
def house(address):
    print('房子在: {}是一座毛坯房。。。'.format(address))


house('杭州西湖')

随着业务拓展,我们不仅要装修房子,还要装修工厂,装修工厂的时候,我们还要知道厂房的面积。装修房子和装修工厂过程相似,只是接收的参数不同,那么我们能不能用相同的装饰器呢?

def decorator(func):
    def wrapper(*args):
        func(*args)
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('精装修房,可以入住啦~~~')

    return wrapper


@decorator
def house(address):
    print('房子在: {} 是一座毛坯房。。。'.format(address))


@decorator
def factory(address, area):
    print('工厂在: {} 是一座毛坯房,建筑面积: {}'.format(address, area))


house('杭州西湖')
factory('杭州西湖', 100)

同理,如果参数有默认值参数,那么形参需要加**kwargs:

def decorator(f):
	pass
	def wrapper(*args, **kwargs):
		pass
		f(*args, **kwargs)
		pass
	pass
	return wrapper

2.2、带返回值

继续以装修房子为例,我们现在要对装修房子做一个预算,看看毛坯房+装修需要花费多少。

def decorator(f):
    def wrapper(*args, **kwargs):
        ret = f(*args, **kwargs)
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('精装修房,可以入住啦~~~')
        ret += 10000
        return ret
    return wrapper


@decorator
def house(address, area):
    print('房子在: {}是一座毛坯房, 面积:{}'.format(address, area))
    return 50000


cost = house('杭州西湖', 100)
print('预计花费:{}'.format(cost))

2.3、装饰器带参

简单示例:

def decrator(*dargs, **dkargs):
    def wrapper(func):
        def _wrapper(*args, **kargs):
            print("装饰器参数:", dargs, dkargs)
            print("函数参数:", args, kargs)
            return func(*args, **kargs)

        return _wrapper

    return wrapper


@decrator(1, 2, a=1, b=2)
def f():
    print('函数执行')


f()

执行顺序:加载decorator->加载f->执行decorator->返回wrapper->执行wrapper->放回_wrapper,f指向_wrapper

  • 解析
    • 返回的wrapper直接执行了

一般装饰器参数很少使用。

2.4、多个装饰器

def decorator_1(f):
    print('decorator_1 start')

    def wrapper(*args, **kwargs):
        print('wrapper_1 start')
        ret = f(*args, **kwargs)
        print('wrapper_1 end')
        return ret

    print('decorator_1 end')
    return wrapper


def decorator_2(f):
    print('decorator_2 start')

    def wrapper(*args, **kwargs):
        print('wrapper_2 start')
        ret = f(*args, **kwargs)
        print('wrapper_2 end')
        return ret

    print('decorator_2 end')
    return wrapper


@decorator_2
@decorator_1
def hello():
    print('hello python')


hello()

可以看到,当多个装饰器装饰同一个函数时,会是一个嵌套的装饰结果,也就是说,先执行完离函数近的一个装饰器,然后再用离函数远的装饰器来装饰执行结果。

2.4、小结

装饰器功能:

  • 引入日志
  • 统计执行时间
  • 执行函数前的预处理
  • 执行函数后的清理功能
  • 权限校验等场景
  • 缓存

通用函数装饰器格式:

def decorator(f):
	pass
	def wrapper(*args, **args):
		pass
		ret = f(*args, **args)
		pass
		return ret
	pass
	return wrapper
	
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-11-28 11:13:24  更:2021-11-28 11:15:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 2:52:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码