导航目录
1. 概念理解
1.1 定义
- 执行特定任务, 完成特定功能的一段代码.
1.2 作用
- 复用
- 隐藏实现细节
- 提高可维护性
1.3 基本形式
def fname([parameters]): code [return variable/expression] fname(arguments)
def dao(x, y): z = x + y return z dao(1, 2)
2. 函数参数
Python 函数的参数有很多变化, 主要从以下三个方面来阐述.
- 按顺序(位置), 还是按指定的参数名称传递和调用?
- 参数的默认值
- 参数的数量
2.1 形参
是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传递的参数。
2.2 位置参数
dao(10 , 20)
2.3 关键词参数
dao(a = 10, b = 20)
2.4 默认参数
在形参中设置默认值, 调用函数传入实参时如果不传入参数, 则使用默认值; 如传入参数则使用实参.
def dao(a, b, c=100): # 含有默认值的参数, 必须置于不含默认值参数的后面. print(a, b , c) dao(86, 32) # 此处调用函数时, 并未传入第三个实参, 但因为在形参中给其设置了默认值, 故运行时会自动使用默认值.
2.5 参数传递
2.6 可变形参
2.6.1 数量可变的顺序参数
def dao(*args): print(args) dao(10, 20)
2.6.2 数量可变的关键字参数
def dao(**args): print(args) dao(a = 10, b = 20)
2.7 实参
2.8 可变实参
def dao(a, b, c): print(a, b , c) dict = { 'a' : 1, 'b' : 2, 'c' : 3, } dao(**dict)
3. return
4. 闭包函数
4.1 概念理解
为什么会有闭包? 出于各种原因,有时候需要在函数外部访问函数内的数据。但由于Python中作用域的约束, 子对象会一级一级地向上寻找所有父对象的变量,就导致这一点通常是无法实现的。
def outer(): v =100; print(v)
很显然此时, 程序会报错: NameError: name ‘v’ is not defined. 在函数外部, 无法调用函数内部的变量v.
所以问题来了, 如果想在函数外部访问函数内部的数据, 该怎么做?
def outer(a): # 定义外部函数 b = 10 # 定义一个外部函数的变量b def inner(): # 定义内部函数 return a + b # 为内部函数添加简单的功能, 并用return返回. return inner # 外部函数被调用后, 返回内部函数. (这里是突破函数作用域约束, 让内外函数进行沟通得关键之处.) outer(9)() # 如所期望的, 输出结果19, 这表明outer函数内部的变量b, 在它的外面被访问到了.
那么此时, 内部函数, 即被称为 “闭包”.
4.2 简单总结
- 闭包是一个函数
- 闭包函数是由其他代码生成的
- 闭包函数携带了生成环境的信息
- 闭包可以让一个变量常驻内存
- 闭包可以避免变量被修改
5. 装饰器
5.1 定义
- 装饰器本质上是一个函数,用来对另一个函数(被装饰的函数对象)在不改动代码的前提下做功能上的补充, 如增加身份或权限验证、插入日志等。
- 装饰器以被装饰的函数对象为输入参数,返回一个新的对象。
- 装饰器的概念本身不难理解,可能令初学者最感到困惑的是,如何在装饰器函数和被装饰的函数对象之间建立联系。
5.2 实例
我们想象这样一个情景:
- 你喜欢玩LOL和TOC.
- 可技不如人, 抑或运气不佳, 联盟总输, 云顶总第八, 于是想到外挂.
- 这样一来, 游戏体验大幅上升, 但还剩最后一个”不是问题的问题”.
- 每次打开游戏前, 需要先打开外观. 游戏结束后, 需要关闭外挂 — 这对于任性有钱的你而言, 很麻烦.
- 所以你打算聘请一个无所不能的, 智能的秘书, 她总能在你想玩游戏的3分钟前, 替你打开外挂.
# 1. 你喜欢玩LOL和TOC.
def play_lol():
print("玩英雄联盟")
def play_toc():
print("玩云顶之弈")
# 2/3/4 每次打开游戏前, 需要先打开外观. 游戏结束后, 需要关闭外挂 -- 这对于任性有钱的你而言, 很麻烦.
def play_lol():
print("玩英雄联盟")
def play_toc():
print("玩云顶之弈")
print("打开外挂")
play_lol()
print("关闭外挂")
print("打开外挂")
play_toc()
print("关闭外挂")
# 所以你打算聘请一个无所不能的, 智能的秘书, 她总能在你想玩游戏的3分钟前, 替你打开外挂.
def assistant(game):
def inner():
print("打开外挂")
game()
print("关闭外挂")
return inner
def play_lol():
print("玩英雄联盟")
def play_toc():
print("玩云顶之弈")
assistant(play_lol)()
assistant(play_toc)()
# 所以你打算聘请一个无所不能的, 智能的秘书, 她总能在你想玩游戏的3分钟前, 替你打开外挂.2
# 为了便于理解, 这里做了一个小调整, 将函数assistant(play_lol)赋值给变量, 使用时调用变量即可.
def assistant(game):
def inner():
print("打开外挂")
game()
print("关闭外挂")
return inner
def play_lol():
print("玩英雄联盟")
def play_toc():
print("玩云顶之弈")
play_lol = assistant(play_lol)
play_toc = assistant(play_toc)
play_lol()
play_toc()
5.2.1 执行流程
- 假设现在想玩LOL, 那么调用函数assistant(play_lol)
- 进入到assistant(play_lol)内部的功能代码
- assistant(play_lol)的返回结果是 return inner
- assistant(play_lol)()即是inner()
- 执行inner函数
- 开外挂
- 玩游戏 play_lol()
- 关外挂
5.3 装饰器的雏形
def assistant(game):
def inner():
print("打开外挂")
game()
print("关闭外挂")
return inner
@assistant
def play_lol():
print("玩英雄联盟")
@assistant
def play_toc():
print("玩云顶之弈")
# play_lol = assistant(play_lol) 相当于 @assistant
# play_toc = assistant(play_toc) 相当于 @assistant
play_lol()
play_toc()
5.4 带参数的装饰器
- 需求升级: 玩游戏, 开外挂, 需要账号和密码, 玩英雄联盟时, 还需要设置想玩的英雄.
def assistant(game):
def inner(*args, **kwargs): #不定形参
print("打开外挂")
game(*args, **kwargs)
print("关闭外挂")
return inner
@assistant
def play_lol(username, password, champion):
print("玩英雄联盟")
print(username, password, champion)
@assistant
def play_toc(username, password):
print("玩云顶之弈")
print(username, password)
# play_lol = assistant(play_lol)
# play_toc = assistant(play_toc)
play_lol("jin", "123456", "kasha")
play_toc("xin", "123456")
5.4.1 参数调用说明
在形参中:
*args 传递可变的顺序参数给实参, 其形式是元组
**kwargs 传递可变的关键字参数给函数实参, 其形式是列表
在实参中:
*args 将元组形式的形参, 解散成字符串
**kwargs 将列表形式的形参, 解散成字符串
5.5 带 返回值的装饰器
5.6 装饰器总结
- 从代码可以看出, 函数里的play_lol = assistant(play_lol) 相当于 装饰器里的@assistant, 所以装饰器实际上是一种语法糖, 不使用装饰器, 也一样可以实现.
- 装饰器本质是一个闭包, 即外部函数调用内部函数数据, 在不改动代码的前提下做功能上的补充.
- 装饰器的用途: 比如想统计某段代码执行所需的时间, 那么可以在其前后调用装饰器.
本站文章除单独注明外均为原创,本文链接https://bowmanjin.com/137,未经允许请勿转载。
请先
!