Python语法查缺补漏 第二章:函数
一、不定长参数
不定长参数,即在调用函数时可以接收任意数量的实参,这些实参在传递给函数时会被封装成元组(位置参数)或字典(关键字参数)形式。
def func(name, *args, **kwargs)
二、拆分参数列表
1. 拆分位置参数
def SumVal(*args):
sum = 0
for i in args:
sum += i
print(sum)
ls = [1, 2, 3]
SumVal(*ls)
提示: *ls的作用是把列表ls中的所有元素拆分出来作为SumVal的实参,即等价于Sumval(1, 2, 3)。
2. 拆分关键字参数
def Info(name, score, country):
print(name, score, country)
d= {'country':'China', 'score':87.32, 'name':'Lihua'}
Info(**d)
提示: **d的作用是把字典中的所有元素拆分出来作为Info的实参,即等价于Info(country=‘China’, score=87.32, name=‘Lihua’)。
三、包
Python中的包(Package)的作用与操作系统中文件夹的作用相似,利用包可以将多个关系密切的模块组成在一起,一方面方便进行各脚本文件的管理,另一方面可以有效避免模块命名冲突问题。
定义一个包,就是创建一个文件夹并在该文件夹下创建一个__init__.py文件,文件夹的名字就是包名。另外,可以根据需要在该文件夹下再创建子文件夹,子文件夹中创建一个__init__.py文件,则又形成了一个子包。
其中__init__.py文件可以是一个空文件,也可以包含包的初始化代码或者设置__all__列表。如果一个模块定义了列表__all__,则from模块名import *语句只能导入__all__列表中存在的表示符。例如对于包含了两个函数func1和fun2的function.py文件,如果在第一行加入__all__ = ['func1']
,则通过from function import *
只能导入function模块中的func1,而不会导入func2。
四、猴子补丁
猴子补丁是指在运行时动态替换已有的代码,而不需要修改原始代码。
def func():
print('func')
def new_func():
print('new_func')
func = new_func
func()
输出为:
new_func
即func函数被new_func函数给取代了。
猴子补丁主要用于在不修改已有代码情况下修改其功能或增加新功能的支持。
例如,在使用第三方模块时,模块中的某些方法可能无法满足我们的开发需求。此时,我们可以在不修改这些方法代码的情况下,通过猴子补丁用一些自己编写的新方法进行替代,从而实现一些新的功能。
五、变量的作用域
1. 局部变量
在一个函数中定义的变量就是局部变量(包括形参),其作用域是从定义局部变量的位置至函数结束位置。
2. 全局变量
在所有函数外(“即代码主体”)中定义的变量就是全局变量,其在所有函数中都可以使用。
在函数中定义global变量,即可使得声明的变量变为全局变量,即可影响代码主体中声明的变量。
def func1():
x = 10
def func2():
global x
x = 10
x = 5
func1()
print(x)
func2()
print(x)
输出为:
5
10
六、高阶函数
高阶函数指的是把函数作为参数的一种函数。
函数不仅可以赋给形参,也可以赋给普通变量。赋值后,即可用变量名代替函数名完成函数调用。
def Upper(f, a, b):
print(f(a) + f(b))
def square(a):
return a ** 2
Upper(square, 1, 2)
输出为:
5
即1x1+2x2=5。
七、lambda函数
lambda函数也称为匿名函数,是一种不使用def定义函数的形式,其作用是能快速定义一个简短的函数。
lambda函数的函数体只是一个表达式,所以lambda函数通常只能实现比较简单的功能。
fun = lambda x, y: x ** 2 + y ** 2
print(fun(3, 4))
输出为:
25
八、函数嵌套
在Python中,函数的定义可以嵌套,即在一个函数的函数体中可以包含另一个函数的定义。
def outer():
x = 10
def inner(): # 在outer中定义嵌套函数inner
x = 20
print('inner,', x)
inner() # 在outer中调用inner函数
print('outer,', x)
outer()
输出为:
inner, 20
outer, 10
1. nonlocal关键字
通过nonlocal关键字,可以使内层的函数直接使用外层函数中定义的变量。(类似于global的感觉)
def outer():
x = 10
def inner(): # 在outer中定义嵌套函数inner
nonlocal x # nonlocal变量
x = 20
print('inner,', x)
inner() # 在outer中调用inner函数
print('outer,', x)
outer()
输出为:
inner, 20
outer, 20
2. 闭包
如果内层函数使用了外层函数中定义的局部变量,并且外层函数的返回值是内层函数的引用,就构成了闭包。
定义在外层函数中但由内层函数使用的变量被称为自由变量。一般情况下,如果一个函数结束,那么该函数中定义的局部变量就会被释放。然而,闭包是一种特殊情况。 外层函数在结束时会发现其定义的局部变量将来会在内层函数中使用,此时外层函数就会把这些自由变量绑定到内层函数。
所谓闭包,实际上就是将内层函数的代码以及自由变量打包在了一起。
def outer(x):
y = 10
def inner(z): # 在outer中定义嵌套函数inner
nonlocal x, y # nonlocal变量
return x + y + z
return inner # 返回嵌套函数inner的调用
f = outer(5)
g = outer(50)
print(f(20), g(20), f(30), g(30), outer(5)(20))
输出为:
35,80,45,90,35
闭包的作用在于可以封存函数执行的上下文环境。例如,通过两次调用outer函数形成了两个闭包,这两个闭包具有相互独立的上下文环境(一个闭包中x=5,y=10;另一个闭包中x=50,y=10),且每个闭包可多次调用。
3. 装饰器
利用装饰器,可以在不修改已有函数的情况下向已有函数中注入代码,使其具备新的功能。如,可以用装饰器将日志处理、执行时间计算等较为通用的代码注入到不同的函数中,从而使得代码更加简洁。
一个装饰器可以为多个函数注入代码,一个函数也可以注入多个装饰器的代码。
def deco1(f):
def inner1(*args, **kwargs):
print('deco1 begin')
f(*args, **kwargs)
print('deco1 end')
return inner1 # 返回函数inner1的引用
def deco2(f):
def inner2(*args, **kwargs):
print('deco2 begin')
f(*args, **kwargs)
print('deco2 end')
return inner2 # 返回函数inner2的引用
@deco1
def f1(a, b):
print(a + b)
@deco1
@deco2
def f2(a, b):
print(a * b)
if __name__ == '__main__':
f1(1, 2)
print('\n')
f2(1, 2)
输出为:
deco1 begin
3
deco1 end
deco1 begin
deco2 begin
2
deco2 end
deco1 end