函数
什么是函数
函数是可以重复执行的语句块,可以重复使用
作用
- 用于封装语句块,提高代码的重用性
- 定义用户级别的函数
函数定义(创建)
def 函数名(形参列表):
语句块
说明
- 函数的名字就是语句块的名称
- 函数名的命名规则与变量名相同(函数名必须为标识符)
- 函数有自己的名字空间,在函数外部不可以访问函数内部的变量,在函数内部可以访问函数外部的变量,通常让函数处理外部数据需要用参数给函数传入一些数据
- 函数的参数列表可以为空
- 语句部分不能为空,如果为空需要填充
pass
语句
函数调用
函数名(实际调用传递参数列表) # 实际调用传递参数以后称为实参
函数调用说明
- 函数调用是一个表达式
- 如果没有
return
语句,此函数执行完毕后返回None
对象 - 如果函数需要返回其它的对象需要用到
return
语句
return
语句
语法
return [表达式]
作用
用于函数中,结束当前函数的执行,返回到调用该函数的地方,同时返回一个对象的引用关系
说明
-
return
语句后跟的表达式可以省略,省略后相当于return None
- 如果函数没有
return
语句,则函数执行完最后一条语句后返回None
(相当于在最后加了一条return None
语句) - 函数调用一定会返回一个对象的引用
函数的参数传递
位置传递
- 实际参数和形式参数通过位置进行传递的匹配
- 实参个数必须与形参个数相同
def myfun(a, b, c):
print(a, b, c)
myfun(1, 2, 3) # 1, 2, 3
myfun(100, 200, 300) # 100, 200, 300
序列传参
序列传参是在函数调用过程中,用 *
将序列拆解后按位置传参的方式进行参数传递
def myfun(a, b, c):
print(a, b, c)
s = [1, 2, 3]
myfun(*s) # * 表示把s拆成 1,2,3,打印结果为 1,2,3
s2 = "ABC"
myfun(*s2) # * 表示把s2拆成 'A','B','C' 打印结果为 A,B,C
关键字传参
- 关键字传参是指传参时,按着形参的名称给形参赋值
- 实参和形参按名称进行匹配
- 实参和形参可以不按位置匹配
def myfun(a, b, c):
print(a, b, c)
myfun(a=99, b=88, c=188) # 99, 88, 188
myfun(b=22, c=33, a=11) # 等同于myfun(11,22,33)
myfun(c=3, b=2, a=1) # 1, 2, 3
字典关键字传参
- 指实参为字典,将字典用
**
拆解后进行关键字传参 - 字典的键名和形参名必须一致
- 字典键名必须为字符串
- 字典的键名要在形参中存在
def myfun(a, b, c):
print(a, b, c)
myfun(**{'c': 3, 'b': 2,'a':1) # 1 2 3
myfun(**{'d': 3, 'b': 2,'a':1}) # 报错,字典的键名和形参名必须一致
myfun(**{'c': 3, 'b': 2,'a':1,'d':4}) # 报错,字典的键名都要在形参中存在
综合传参
- 函数传参方式,在能确定形参能唯一匹配到相应实参的情况下可以任意组合
- 传参时先位置传参,后关键字传参
def myfun(a, b, c):
pass
myfun(100, *[200, 300]) # 正确
myfun(*'AB', 300) # 正确
myfun(100, c=300, b=200) # 正确
myfun(1, **{'c': 3, 'b': 2}) # 正确
myfun(**{'c': 3, 'b': 2}, a=1) # 正确
myfun(b=2, c=3, 1) # 错误,不能确定1给谁?
函数的缺省参数
语法
def 函数名(形参名1=默认实参1, 形参名2=默认实参2, ...):
- 缺省参数必须自右至左依次存在,如果一个参数有缺省参数,则其右侧的所有参数都必须有缺省参数
- 缺省参数可以有0个或多个,甚至全部都有缺省参数
def info(name, age=1, address="未填写"):
print(name, "今年",age, '岁, 家庭地址是:', address)
info('tarena', 15)
info('小魏', 20, '北京市朝阳区')
info('小李')
def test(a, b=10, c): # 错误
pass
函数的形参定义方式
位置形参
def 函数名(形参名1, 形参名2, ...):
语句块
星号元组形参
- 收集多余的位置传参
- 元组形参名通常用:
args
def 函数名(*元组形参名):
语句
def func(*args):
print(len(args), args)
func(1, 2, 3, 4) # 4, 1, 2, 3, 4
命名关键字形参
- 所有的参数都必须用关键字传参或字典关键字传参传递
-
*
为语法标识符,遇到*
,右边所有的参数必须以关键字传参
def 函数名(*, 命名关键字形参):
语句
或
def 函数名(*args, 命名关键字形参):
语句
def fn(*, d, e):
print("d=", d)
print("e=", e)
fn(d=100, e=200) # 合法调用
fn(1, 2) # 不合法,不能用位置传参
fn(1, 2, d=100, e=200) # 不合法,不能用位置传参
def fm(*args, d, e):
print(args)
print('d=', d)
print('e=', e)
fm(1, 2, d=100, e=200)
# (1, 2)
# d= 100
# e= 200
fm(*"AB", **{'e': 20, 'd':10})
# ('A', 'B')
# d= 10
# e= 20
fm(*[5,6], **{'e': 20, 'd':10})
# (5, 6)
# d= 10
# e= 20
双星号字典形参
- 收集多余的关键字传参
- 通常字典形参名定为:
kwargs
def 函数名(**字典形参名):
语句
def func(**kwargs):
print("关键字参数个数是:", len(kwargs))
print("kwargs =", kwargs)
func(name='Jason', age=15)
# 关键字参数个数是: 2
# kwargs = {'name': 'Jason', 'age': 15}
func(name='Jason', age=15,score = 90)
# 关键字参数个数是: 5
# kwargs = {'name': 'Jason', 'age': 15,'score':90}
func()
# 关键字参数个数是: 0
# kwargs = {}
函数的参数说明
- 缺省参数,位置形参,星号元组形参,命名关键字形参和双号星字典形参可以混合使用
- 函数参数自左至右的顺序为:位置形参,星号元组形参,命名关键字形参,双星号字典形参
def f1(a, b, *args, c, **kwargs):
print(a) # 1
print(b) # 2
print(args) # 3,4
print(c) # 5
print(kwargs) # {'d':7,'e':7}
f1(1, 2, 3, 4, d=6, c=5, e=7)
# a = 1
# b = 2
# args = (3,4)
# c = 5
# kwargs = {'d':7,'e':7}
f1(*"hello",d=6,**{'c':5,'e':7}) # 相当于 f1('h','e','l','l','o',d=5,c=5,e=7)
# a = 'h'
# b = 'e'
# args = ('l','l','o')
# c = 5
# kwargs = {'d':6,'e':7}
函数的不定长参数
可以接收任意的位置传参和关键字传参
def fn(*args, **kwargs):
print(args)
print(kwargs)
fn()
# args = (), kwargs = {}
fn(1,2,3,4)
# args = (1, 2, 3, 4), kwargs = {}
fn(1,2,3,'a','b',c=4,d=5,**{'e':7,'f':8})
# args = (1, 2, 3, 'a', 'b'), kwargs = {'c': 4, 'd': 5, 'e': 7, 'f': 8}
函数变量
函数名是变量,它在创建函数时绑定一个函数
def f1():
print("f1被调用")
fx = f1
fx() # 等同于 f1()
del f1 # 对fx没影响
# ***************************************************
def f1():
print("hello")
def f2():
print("world")
f1, f2 = f2, f1 # 交换两个变量的绑定关系
f1() # world
函数作为参数和返回值
- 一个函数可以作为另一个函数的参数传递
def f1():
print("hello")
def f2():
print('world')
def fx(fn):
print(fn)
fn() #
fx(f1)
# <function f1 at 0x000001F2F48CC1E0> 函数在内存中的地址
# hello
fx(f2)
# <function f2 at 0x000001F2F6598A60> 函数在内存中的地址
# world
# 示例
def fx(a, fn):
return fn(a)
L = [1,2,3,4]
print('最大值是:', fx(L, max)) # 4
print('最小值是:', fx(L, min)) # 1
print('和是:', fx(L, sum)) # 10
- 函数可以返回另一个函数,即函数为作函数的返回值
def get_fx():
s = input('请输入您要做的操作: ')
if s == '求最大':
return max
elif s == '求最小':
return min
elif s == '求和':
return sum
L = [2,4,6,8,10]
print(L)
f1 = get_fx()
print(f1(L))
函数嵌套定义
函数的嵌套定义是指一个函数里用 def
语句来创建其它的函数
def fn_outer():
print("fn_outer被调用!")
def fn_inner():
print("fn_inner被调用")
fn_inner()
print('fn_outter调用结束')
retuen fn_inner
fn_outer()
fn_inner() # 报错
fx = fn_outer()
fx() # 调用fn_outer内部的fn_inner()函数
函数的文档字符串
函数内部,第一个没有赋值给任何变量的字符串为文档字符串
def 函数名(形参列表):
'''函数的文档字符串'''
函数语句块
函数的属性
-
__doc__
属性用于绑定该函数的文档字符串 -
__name__
属性用于绑定函数名的字符串
函数定义语句
# def语句的语法
# 完整的函数定义语句
[@装饰器名1] # 详见系列文章Python之装饰器
[@装饰器名2] # 详见系列文章Python之装饰器
...
def 函数名([位置形参],[*[元组形参名]], [命名关键字形参], [**字典形参]):
'''文档字符串'''
语句块
全局变量和局部变量
局部变量
- 定义在函数内部的变量称为局部变量(函数的形参也是局部变量)
- 局部变量只能在函数内部使用
- 局部变量在函数调用时才能够被创建,在函数调用之后会自动销毁
- 在函数内首次对变量赋值是创建局部变量,再次为变量赋值是修改局部变量的绑定关系
- 在函数内部的赋值语句不会对全局变量造成影响
- 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个模块范围内访问
全局变量
- 定义在函数外部,模块内部的变量称为全局变量
- 全局变量,所有的函数都可以直接访问(但函数内部不能将其直接赋值)
a = 100
b = 200
def fx(c):
d = 400
print(a, b, c, d)
fx(300)
print('a =', a) # a = 100
print('b =', b) # b = 200
print('c =', c) # 出错,不能访问局部变量
print('d =', d) # 出错,不能访问局部变量
def fy(c):
d = 40
a = 10 # 此时会创建局部变量a,不会修改全局变量a
print(a, b, c, d)
fy(30) # 10, 200, 30, 40
globals
函数和 locals
函数
-
globals()
返回当前全局作用域内变量的字典 -
locals()
返回当前局部作用域内为量的字典
a = 1
b = 2
c = 3
def f1(c, d):
e = 300
print(locals()) # {'c': 100, 'd': 200, 'e': 300}
print(globals()) # 返回结果中包含a,b,c,f1等全局变量
print(c) # 100
print(globals()['c']) # 返回全局变量的c变量的值
f1(100, 200)
Python作用域
作用域也叫名字空间,是访问变量时,查找变量名的范围空间
Python的四个作用域LEGB
- 局部作用域
Local function
简称L
- 外部嵌套函数作用域
Enclosing Function Locals
简称E
- 函数定义所在模块(文件)的作用域
Global(Mudule)
简称G
- Python 内置模块的作用域
Builtin(python)
简称B
变量名的查找规则
L --> E --> G --> B
- 在默认情况下,对变量名赋值会创建或改变本作用域内的变量
v = 100 # 全局作用域
def fun1():
v = 200 # 外部嵌套函数的作用域
print('fun1内的v=', v)
def fun2():
v = 300 # 局部作用域
print("fun2内的v=", v)
fun2()
fun1()
# fun1内的v= 200
# fun2内的v= 300
print("v =", v) # v = 100
# ****************************************************** #
v = 100 # 全局作用域
def fun1():
v = 200 # 外部嵌套函数的作用域
print('fun1内的v=', v)
def fun2():
print("fun2内的v=", v)
fun2()
fun1()
# fun1内的v= 200
# fun2内的v= 200
print("v =", v) # v = 100
global
语句
作用
- 告诉解释器,
global
语句声明的一个或多个变量,这些变量的作用域为模块级的作用域,也称作全局变量 - 全局声明
global
将赋值变量映身到模块文内部的作用域
语法
global 变量1, 变量2, ...
v = 100
def fn():
global v
v = 200
fn()
print(v) # 200
说明
- 全局变量如果要在函数内部被赋值,则必须经过全局声明(否则会被认为是局部变量)
- 全局变量在函数内部不经过声明就可以直接访问
- 不能先声明局部的变量,再用
global
声明为全局变量,此做法不附合规则 -
global
变量列表里的变量不能出现在此作用域内的形参列表里
# 不能先声明局部的变量,再用 global 声明为全局变量,此做法不附合规则
def fx():
x = 100 # 此处会出现语法警告
global x
x = 200
# global 变量列表里的变量不能出现在此作用域内的形参列表里
def fx(v):
global v # 报错
v = 200
nonlocal
语句
作用
*告诉解释器,nonlocal
声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量
语法
nonlocal 变量名1, 变量名2, ...
def f1():
var = 200
print("f1里的var=", var) # 200
def f2():
nonlocal var
var = 300
print("f2里的var=", var) # 300
f2()
print("f2调用结束后f1里的var值为", var) # 300
f1()
print('全局的var =', var) # 100
说明
-
nonlocal
语句只能在被嵌套函数内部进行使用 - 访问
nonlocal
变量将对外部嵌套函数的作用域的变量进行操作 - 当有两层或两层以上的函数嵌套时,访问
nonlocal
变量只对最近一层的变量进行操作 -
nonlocal
语句的变量列表里的变量名,不能出现在此函数的参数列表中
# 1. nonlocal语句只能在被嵌套函数内部进行使用
def f1():
# nonlocal x # 这是错的,因为没有外部嵌套函数
x = 100
f1()
# 3. 当有两层或两层以上的函数嵌套时,访问nonlocal变量只对最近一层的变量进行操作
def f1():
v = 100
def f2():
v = 200
def f3():
nonlocal v # 只对f2里的v进行操作
v += 1
f3()
print("f2最后的v=", v)
f2()
print('f1最后的v=', v)
f1()
# 4. nonlocal语句的变量列表里的变量名,不能出现在此函数的参数列表中
def f1():
v = 100
def f2(v):
# nonlocal v # 出错,v已在形参列表中...
v += 1
f2(20)
f1()
lambda
表达式(匿名函数)
作用
创建一个匿名函数对象,同 def 类似,但不提供函数名
语法
lambda [参数1, 参数2, ...]: 表达式
-
lambda
只是一个表达式,它用来创建一个函数对象 -
lambda
表达式调用时,先执行冒号后:
的表达式,并返回表达式的结果的引用 -
lambda
表达式创建的函数只能包含一条表达式
-
lambda
比函数简单,且可以随时创建和销毁,有利于减少程序的偶合度
def myadd(x, y):
return x + y
# 以上函数可以改写为:
myadd = lambda x, y: x + y
print('2 + 3 =', myadd(2, 3))
# ******************************************* #
res = lambda x:(x**2+1) % 5 == 0
print(res(3)) # True
print(res(4)) # False
# ****************************************** #
res = lambda x,y:x if x > y else y
print(res(3,4)) # 4
print(res(2,1)) # 2
# ******************************************* #
def fx(f, x, y):
print(f(x, y))
fx((lambda a, b: a + b), 100, 200) # 300
fx((lambda a, b: a ** b), 3, 4) # 81