- 具有特定功能的代码块
- 意义:①简化代码重复率;
②功能模块化
一. 内置函数
用法: 函数名[参数]
返回: seq / None
print, abs,
二、自定义函数
1. 语法格式
def 函数名([参数]):
函数体
[pass 为占位符]
[return 返回值]
2. 参数使用
--- 函数的参数只在定义时创建一次,之后再次调用函数,不会给变量新创建内存
(1) 位置参数(必须参数)
--- 一旦定义,除默认参数必须按照顺序传入,位置固定
> 位置参数必须放在最前面
(2) 默认参数
--- 给参数赋予默认值,如果不传入,使用默认值
> 默认形式参数不要使用可变类型,否则重复调时,默认值会被修改
(3) 命名关键字参数 - *,
def 函数名(*, 参数名, 参数名...):
#'*,',关键字参数和命名关键字参数的传参,必须通过【参数名= 参数值】形式传入
> 调用
①只能【参数名= 参数值】形式传入
②顺序不需要固定
> 优点
① 增加程序可读性
② 忽略参数的作用
③ 当参数有默认值时,等同于默认参数
④ 除了指定默认值,必须传入参数
(4) 可变参数 - * args
--- 用来收集所用的位置参数,打包成一个元组
def 函数名(* args):
> args 为元组,因为可变参数函数定义时,可以把零散位置参数打包成元组
> 对于元组或者列表(args或者自定义传入值),应该使用“*”解包
(5) 关键字参数 - ** kwargs
--- 把命名关键字打包成字典
def 函数名(** kwargs):
(6) 万能参数
* arg, ** kwargs
注意:
(1) 位置参数必须在最前面
(2) 命名关键字参数不能和可变参数放在一起
(3) 优先顺序:
位置参数 > 默认参数 > 命名关键字参数 / 可变参数 > 关键字参数
def fu1(a,b,c=0,*args, **kwargs):
>>> 前三个参数被赋值给abc,多余葡萄普通参数传入args,输入关键字参数,传入kwargs
def fu2(a,b,c=0,*,d, **kwargs):
如果有d,关键字参数优先传入d,其他关键字优先传入kwargs
3. 返回值
> return语句的执行,代表函数的结束
> 返回值只能有一个,如果需要多个值,可以以元组返回;
> 以下返回值为None
(1) return
(2) reutrn None
(3) 不写
> 函数最好传入和返回值都使用元组等不可变类型
4. 函数中的值传递
> 不可变类型的值传递
--- 形参指向传入的实参对象,修改创建新对象,两者互不影响
> 可变类型的值传递
--- 形参指向传入的实参对象,直接修改对象,函数对实参发生影响
5. 命名空间和作用域
<1> 命名空间
(1) 概念
命名空间 : 可以保存名字的容器
> 包括:变量名、函数名、类名
> 命名空间中,名字以key-value字典结构存储,其中key为变量名,value为内存地址
> 每一种命名空间都有固定区域
对于函数:
第一次def时,构建命名空间
对于变量:
第一次赋值时,构建命名空间
(2) 分类
① 内建命名空间
--- python解释器启动的时候创建,解释器关闭时销毁
如: sum, print
② 全局命名空间
--- 读取模块定义的时候创建,程序运行结束,空间销毁
如: 全局变量,顶层函数
③ 局部命名空间
--- 在函数创建时创建,函数执行结束时销毁
如: 局部变量,形式参数, 嵌套函数
注意: 命名空间不存在包含关系,只存在生命周期,或者说作用域不同。
> 各命名空间创建顺序:
python解释器启动 ->创建内建命名空间 -> 加载模块 -> 创建全局命名空间 ->函数被调用 ->创建局部命名空间
> 各命名空间销毁顺序:
函数调用结束 -> 销毁函数对应的局部命名空间 -> python虚拟机(解释器)退出 ->销毁全局命名空间 ->销毁内建命名空间
<2> 作用域
--- 命名空间中的名字起作用的范围
① 内建命名空间 --- 整个运行环境所有模块
② 全局命名空间 --- 仅限当前py文件,使用其他py文件需导入
③ 局部命名空间 --- 仅限函数内部有效
注意: 作用域不存在包含关系,只是大小不同;
文件名,变量名,函数名...不要用内建命名空间变量名
<3> 访问原则
(1) LEGB原则
> 作用域按照变量的定义位置可以划分为4类:.
Local (函数内部) 局部作用域
Enclosing(嵌套函数的外层函数内部)嵌套作用域(闭包)
Global (模块全局) 全局作用域
Built-in (内建) 内建作用域
(2) 名称的访问
> 读取 --- LEGB
> 修改 --- 只从当前最小作用域查找,如果找到修改,找不到创建
globla, nonlocal方法可以修改
> 删除 --- 只能删除当前命名空间名字
(3) global nonlocal
global --- 局部命名空间修改全局命名空间内容
nonlocal --- 局部命名空间修改外围命名空间内容
(4) 显示命名空间
local() --- 可以显示该语句所在位置的命名空间
global() --- 显示全局命名空间
eg.
def f():
k = 'asdf'
def inner():
nonlocal k
k = 'qewr'
# del k 报错,无法删除上一级命名空间
inner()
print(k)
6. lambda表达式(匿名函数)
> 头等函数: 变量和函数类型、函数名可以被赋值、传递、和作为返回值
#函数名赋值
def hello():
print('hello')
hello_new = hello
hello_new()
# 函数名当成返回值
def outer():
def inner():
print('dsaf')
return inner
a = outer()
a()
# 函数名当成值被传递
def hello():
print('hello')
def k(m):
pass
k(hello)
(1) 定义
lambda参数: 返回值表达式
(2) 使用场景
函数体比较简单
from numpy import square
li = [1, 2, 4]
li.sort(key = lambda x: x**2)
li.sort(key = square)
7. 递归
--- 函数调用自身
(1) 直接递归
(2) 间接递归
递归一定要通过条件终止,分为递推和回归两个步骤
> 递归和循环
1. 递归思路简单,但是效率比循环低
2. 递归有最大深度(所有函数调用次数),default = 1000
最大递归次数通过sys.getrecursionlinit()获取
# 斐波那契数列
def fb(n):
if n ==1 or n ==2:
return 1
else:
return fb(n-1)+fb(n-2)
# for斐波那契数列
# 多维列表解包
# 汉诺塔 - 列表
8. 函数注释(文档)
--- 在函数下用三引号
显示:
> print(函数名.__doc)
> help(函数名)
--- 参数形式的标注
def add(a: int, b:float)->int:
print(函数名.__annotation__)