函数
函数简介
- 一个程序由一个个任务组成,函数就是代表一个任务或者一个功能
- 函数是代码复用的通用机制
函数分类
- 内置函数
- 标准库函数
- 第三方库函数
- 用户自己定义函数
函数定义和调用
def 函数名 ([参数列表]):
'''文档字符串'''
函数体/若干语句
- 使用def来定义函数,然后就是一个空格和函数名称
- 在执行def时,会创建一个函数对象,并绑定到函数名变量上
- 调用函数之前,必须要先定义函数,即先调用def创建函数对象
(1)内置函数对象会自动创建
(2)标准库和第三方函数,通过import导入模块时,会执行模块中的def语句
形参和实参
- 形参用于定义,实参用于调用
- 圆括号内是形式参数列表,有多个参数则使用逗号隔开
- 形式参数不需要声明类型,也不需要指定函数返回值类型
- 无参数,也必须保留空的圆括号
- 实参列表必须与形参列表一一对应
def printMax(a,b): #a,b为形参
'''用于比较两个数值大小,输出较大值'''
if a>b:
print(a,"较大值")
else:
print(b,"较大值")
printMax(10,20) #10,20为实参
文档字符串
- 函数的注释,通过三个单引号或三个双引号来实现,中间可以加入多行文字进行说明
- 调用 help(函数名.doc) 可以输出函数的文档字符串
返回值
- 如果函数体中包含return语句,则结束函数执行并返回值
- 如果函数体中不包含return语句,则返回None
- 要返回多个返回值,使用列表、元组、字典、集合将多个值存起来即可
变量的作用域
全局变量
- 在函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始知道模块结束
- 全局变量降低了函数的通用性和可读性。应尽量避免全局变量的使用
- 全局变量一般做常量使用
- 函数内要改变全局变量的值,使用global声明一下
局部变量
- 在函数体(包含形式参数)声明的变量
- 局部变量的引用比全局变量快,优先考虑使用
- 如果局部变量和全局变量同名,则在函数内隐藏全局变量
a = 3 #全局变量
def test01():
b = 4 #局部变量
print(b*a)
参数传递
- 函数传递的本质就是:从实参到形参的赋值操作
- Python中“一切皆对象”,所有赋值操作均为“引用传递”,而非“值传递”
- 具体操作分为两类:
1、对可变对象进行写操作,直接作用与原对象本身
可变对象:字典 列表 集合 自定义的对象
2、对不可变对象进行写操作,会产生一个新的对象空间
不可变对象:数字 字符串 元组 布尔值
浅拷贝
- 浅拷贝:不拷贝对象的内容,只是拷贝子对象的引用。
>>> import copy
>>> a = [1,2,3,[4,5]]
>>> b = copy.copy(a)
>>> print("a:",a)
>>> print("b:",b)
>>> b.append(60)
>>> b[3].append(70)
>>> print("a:",a)
>>> print("b:",b)
a:[1,2,3,[4,5]]
b:[1,2,3,[4,5]]
a:[1,2,3,[4,5,70]]
b:[1,2,3,[4,5,70],60]
深拷贝
- 深拷贝:子对象的内存也全部拷贝一份,对子对象的修改不会影响源队形
- 连根拔起
>>> import copy
>>> a = [1,2,3,[4,5]]
>>> b = copy.deepcopy(a)
>>> print("a:",a)
>>> print("b:",b)
>>> b.append(60)
>>> b[3].append(70)
>>> print("a:",a)
>>> print("b:",b)
a:[1,2,3,[4,5]]
b:[1,2,3,[4,5]]
a:[1,2,3,[4,5]]
b:[1,2,3,[4,5,70],60]
不可变对象含可变子对象
- 用的是浅拷贝
参数类型
位置参数
- 函数调用时,实参默认按位置顺序传递,需要个数和形参匹配
按位置传递的参数,称为位置参数
默认值参数
- 可以为某些参数设置默认值,这样这些参数在传递时就是可选的
默认值参数放到位置参数后面
def f1(a,b,c=10,d=20): #默认值参数放在后面
print(a,b,c,d)
f1(8,9)
f1(1,2,3,4) #覆盖默认值
命名参数
- 按照形参的名称传递参数,称为命名参数或者关键字参数
位置可以不管
def test01(a,b,c)
print(a,b,c)
test01(c=1,b=3,a=2)
可变参数
- 可变参数指的是可变数量的参数
- *param(一个星号),将多个参数收集到一个元组对象中
- **param(两个星号),将多个参数收集到一个字典对象中
>>> def f2(a,b,*c):
>>> print(a,b,c)
>>> f2(1,2,3,4,5,6)
1 2 3 (4,5,6)
>>> def f2(a,b,**c):
>>> print(a,b,c)
>>> f2(1,2,name='wwy',age=18)
1 2 {'name':'wwy','age':18}
强制命名参数
- 在带星号的可变参数后面增加新的参数,必须在调用的时候强制命名参数
def f3(*a,b,c):
print(a,b,c)
f3(2,3,4) #会报错,因为a是可变参数,将2,3,4全部收集,造成b和c没有赋值
f3(2,b=3,c=4) #强制命名
lambda表达式和匿名函数
- lambda表达式实际上就是一种函数
- 特殊的是,一行包含的函数命名的所有要素,其格式为:
lambda arg1,arg2,arg3…:<表达式> - 其中,arg为参数,<表达式>为函数体
f = lambda a,b,c:a+b-c
print(f(2,3,4))
eval()函数
- 将字符串str当成有效的表达式来求值并返回计算结果。格式如下: eval(source[,globals[,locals]])->value
- source是一个Python表达式或函数
- compile()返回的代码对象
- globals是dictionary
- locals任意映射对象
递归函数
- 递归函数是说自己调用自己的函数,在函数体内直接或间接调用自己
- 每个递归函数必须包含两个部分:
- 终止条件
- 递归步骤
嵌套函数
-
嵌套函数:在函数内部定义的函数
-
外部无法调用内部函数
-
何时使用嵌套函数?
- 封装-数据隐藏
- 在函数内部避免代码重复
- 闭包
def f1()
print('f1 running...')
def f2() #只有f1能调用f2
print('f2 running...')
f2()
f1()
nonlocal 关键字
- nonlocal:用来声明外层的局部变量
- global:用来声明全局变量
a = 100
def outer():
b = 10
def inner():
nonlocal b #声明外部函数的局部变量
print("inner:",b)
global a #声明全局变量
a = 1000
inner()
print("outer:",b)
outer()
print("a:",a)
LEGB规则
- Python在查找名称时,是按照LEGB规则查找的:
Local —> Enclosed —>Global —>Built in
名称 | 含义 |
---|---|
Local | 函数或类的方法内部 |
Enclosed | 嵌套函数 |
Global | 模块中的全局变量 |
Built in | Python为自己保留的特殊名称 |