Python程序色设计基础第五章
文章目录
5.1 函数定义与使用
5.1.1 基本语法
基本语法:
-----def 函数名([参数列表]):
-----‘’‘ 注释 ’‘’
----------函数体
一定要严格保持缩进。
可以使用内置函数 help() 来查看注释。
函数的返回值和 return 的值数据类型相同。
无论 return 语句出现在函数的什么位置,一旦得到执行,直接结束函数的执行。若果函数没有 return 语句,或者又 return 语句但是没有得到执行,或者执行了不返回任何值的 return 语句,解释器都会认为该函数以 return None 结束。
5.1.2 函数嵌套定义、可调用对象与修饰器
函数嵌套定义
在函数 A 的函数体内定义函数 B,函数 A 返回函数 B。
可调用对象
函数属于 python 的可调用对象之一,调用方法为:
调用:变量 = 函数名[(实参)]
使用:变量([实参])
def test1(a,b):
def func(x):
return a+b+x
retrun func #这里 return func 而没有用 return func([形参])
def test2(a,b):
def func(x):
return a+b+x
retrun func(a) #func(a) 中的 a 就是 test(a,b) 中的 a
a = test1(1,2)
b = test2(1,2)
a(3) ==>6
b ==>4
test1(2,2)(3) ==>7
test2(2,2) ==>6
修饰器
修饰器本质上是一个一函数为参数,返回函数的函数。
5.1.3 函数递归调用
返回本函数(不止是返回函数名,还包括参数,即整个函数的运行),只不过每次返回对参数进行修改,知道参数满足一定的要求,不再返回函数,而是一个确定的值。
5.2 函数参数
5.2.1 位置参数
是一种常用的参数形式,调用函数的实参和形参顺序必须严格一致,数量必须相同。
5.2.2 默认值参数
在函数定义时,为参数设置默认值,在调用函数时是否为此种参数传递实参时可选的,若为默认值参数传递其他实参,位置和数量必须符合。
在函数定义时,一个默认值参数的后面都不能再出现位置参数。
可以用 函数名.–defaule-- 来查看函数当前所有的默认值,返回一个元组。
要尽量避免用可变序列作为函数的默认值参数。
def test(new,old=[]):
old.append(new)
return old
test('5',[1,2,3,4]) ==>[1, 2, 3, 4, '5']
test('c',['a','b']) ==>['a', 'b', 'c']
test('a') ==>['a'] #第一次使用默认列表参数
test('b') ==>['a', 'b'] #默认列表变为 ['a']
5.2.3 关键参数
在实参列表中,为形参赋值
def test(a,b,c):
print(a,b,c)
test(b=1,a=2,c=3) ==>2 1 3 #如果所有参数都是关键参数,名称对应好即可
test(a=1,2,3) ==>SyntaxError: positional argument follows keyword argument
test(c=1,2,3) ==>SyntaxError: positional argument follows keyword argument
test(1,c=3,b=2) ==>1 2 3 #如果只有部分是关键参数,默认值参数要在前面,后面的关键参数名称对应好
5.2.4 可变长度参数
第一种可变长度参数,将参数保存在元组中,实参形式为位置参数:
def test(*p):
print(p)
test(1,2,3) ==>(1,2,3)
第二种可变参数,将参数保存在字典中,实参形式为关键参数:
def test(**p):
print(p)
test(x=1,y=2,z=3) ==>{'x': 1, 'y': 2, 'z': 3}
#注意,字典里,键为 str([形参]),例如 1 所对应的键为 'x',即字符串化,在实参列表里是 x
5.2.5 传递参数时的序列解包
可变长度参数是形参长度不确定,由实参长度确定;而传递参数的序列解包是形参长度确定,用这个长度的一个或多个序列来作为实参。
第一种,实参非字典序列:
def test(a,b,c,d):
print(a,b,c,d)
x=[1,2]
y=['third':3,'forth':4]
test(*x,*y.values()) ==>1 2 3 4
第二种,实参为字典序列:
def test(a,b,c):
print(a,b,c)
dict1 = {'b':1,'a':2,'c':3}
test(**dict1) ==>2 1 3 #其中,字典的键一定要和形参名分别相同
当可变长度参数遇到序列解包:
def test(*p):
print(p)
lst1 = [1,2,3]
test(*lst1) ==>1 2 3
def test(**p):
for i in p.items():
print(i,end='')
dict1 = {'x':1,'y':2,'z':3}
test(**dict1) ==>('x',1) ('y',2) ('z',3)
多种形式的参数的混合使用
在定义函数时,形参列表应以如下形式排列:
位置参数,默认值参数,可变长度参数*,可变长度参数**
再调用函数时,实参列表应以如下形式排列:
位置参数和可变长度参数*,默认值参数,关键参数,可变长度参数*,可变长度参数**
(可变长度参数* 在实参列表中会按位置参数对待,可变长度参数** 在实参列表中按关键参数对待)
def test(a,b,c):
print(a,b,c)
test(c=2,b=3,1) ==>SyntaxError: positional argument follows keyword argument
#位置参数不能在关键参数之后
test(**{'b':1,'c':2},*(3,)) ==>SyntaxError: iterable argument unpacking follows keyword argument unpacking
#序列解包不能在关键参数解包之后
test(c=2,b=3,*(1,)) ==>1 3 2 #序列解包可以在关键参数之后,但在实参中会按位置参数处理
test(*(1,),**{'c':1,'b':2}) ==>1 2 1
5.3 变量作用域
不同作用域的变量名是互不影响的。
若在函数内部定义了一个与函数外变量同名的局部变量,后面的代码都以局部变量的值为准。
若没有定义同名的局部变量,以全局变量的值为准。
可以用 global 变量 在函数内定义一个全局变量,但定义一个全局变量时,只能有定义操作,不能有赋值 global a = 1 是错误的。global a \n a = 1 是正确的。
x=1
def print_x():
print(x,end = ' ')
y=x
print(y)
print_x() ==>1 1
def change_x():
x=3
print(x)
change_x() ==>3
def change_x():
print(x)
x=3
change_x() ==>UnboundLocalError: local variable 'x' referenced before assignment
#当在函数内确实要引入局部变量时,要在定义变量之后再使用,即使在函数外面有同名的全局变量
def demo():
print(x)
x=x+1
print(x)
demo(x) ==>UnboundLocalError: local variable 'x' referenced before assignment
#原理同上,x = x +1 这个表达式中,先计算右边,右边是全局变量,为 1,左边是局部变量,在定义之前
#的 print(x) 的 x 是局部变量 x ,在定义前使用,报错
def local_x():
x=3
print(x) ==>1 #局部变量不改变外面的值
5.4 lambda 表达式
语法格式:
lambda [形参] : 表达式
相当于函数体只有 return 语句的函数:
def f([形参]):return 表达式
def test(n):
return n**2
lst1 = [1,2,3]
list(map(lambda x:test(x), lst1)) ==>[1,4,9] #lambda 中函数的嵌套
r = []
for i in range(3):
r.append(lambda :i**2)
r ==>[<function __main__.<lambda>()>,
<function __main__.<lambda>()>,
<function __main__.<lambda>()>] #封装了三个 lambda 函数,返回值为 i**2
func1 = r[1]
func2 = r[2]
func3 = r[3]
print(func1(),func2(),func3()) ==>4 4 4
#是因为,r 中的 lambda 表达式是无参函数,返回值是 i**2 ,此时 i 已经在 range(3) 中迭代完成,
#i == 2 ,func1(), func2() ,func3() 的值都是 2**2 == 4
r = []
for i in range(3):
r.append(lambda n=i:n**2) #相当于使用了默认值参数
r[0]() ==>0
r[1]() ==>1
r[2]() ==>4
r[0](5) ==>25