Python 学习日记3
——函数和Lambda表达式
3.1 函数
函数是代码复用的重要手段,使程序更加简洁。
定义函数要明白以下几点
- 函数需要动态变化的数据,即为函数定义的参数;
- 函数需要传出调用函数后得到的数据,这些数据应被定义为返回值。
- 函数具体实现的过程,即函数主体。
3.1.1 定义和调用函数
定义函数的语法格式:
def 函数名(参数列表):
...
函数主体
...
[return[返回值]]
- 函数名只要是一个合法的标识符即可
- 形参列表:参数之间以逗号隔开
- retuen语句可以显式的返回一个值,这个值可以是有具体值的变量也可以是一个表达式。
示例代码:
def my_fun(x,y):
z=x if x>y else y
return z
result=my_fun(8,15)
print('result:',result) #输出结果:15
有多个返回值时
如果程序需要多个返回值,则既可以把多个值包装成列表之后返回,也可以直接返回多个值。如果Python函数直接返回多个值,Python会自动将多个返回值封装成元组。
3.1.2 递归函数
函数不仅可以调用其他函数也可以调用函数自身,即为函数递归。函数递归包含了一种隐式的循环,它会重复执行某段代码,但是这种重复执行无需循环控制。经典的例子有求斐波那契数列、求阶乘和求幂等。
递归一定要向已知方向进行:在某个时刻函数的返回值是确定的,即不再调用它自身,否则递归就成了无穷递归,类似死循环。
示例:斐波那契数列
def fibonacci(i):
if i<=2 and i>0:
return 1
else:
return (fibonacci(i-2)+fibonacci(i-1))
for j in range(1,11):
print(fibonacci(j),end=' ') #打印斐波那契数列前十位数字
1 1 2 3 5 8 13 21 34 55
3.2 函数的参数
3.2.1 关键字参数、位置参数
Python函数的参数名不是无意义的,其允许在调用函数时通过名字来传入参数值。
按照参数位置传入的为位置参数,它是按位置顺序传入的;如果根据参数名来传入参数,则位置顺序就无关紧要。
def Data(width,height):
return(2*(width*height))
print(Data(4,5)) #根据位置顺序传入参数
print(Data(height=5,width=4)) # 根据关键字传入参数,可调换位置
但是,要求在调用函数时关键字参数关键字参数必须位于位置参数之后。
3.2.2 参数收集与逆向参数收集
- 参数收集
很多语言都允许定义个数可变的参数,这样可以在嗲用函数时传入任意多个参数。
Python也一样,其方法实在形参前面添加一个星号 ‘*’,与序列在封包时一样,表示该参数可以接收多个参数值,这些值被当成元组传入。
Python还可以收集关键字参数,会将这些参数收集成字典,此时需要在参数前面添加两个星号。
- 逆向参数收集
逆向收集参数即值在程序已有列表、元组等对象的前提下,把他们的元素拆开之后传给函数的参数。
方法也一样,在需要传入的列表元组参数之前添加一个星号,在字典参数之前添加两个星号。
3.2.3 参数的传递机制
Python中函数的参数传递机制都是‘值传递’。所谓值传递,就是将实际参数值的副本(复制品)传入函数,而参数本身不会受到任何影响。
- 不管什么类型的参数,在函数中对函数直接使用“=”符号赋值是没有用的,直接使用等号赋值并不能改变参数。
- 如果要让函数修改某些数据,则可以通过把这些数据包装成列表、字典等可修改对象,然后把列表、字典等可变对象作为参数传入函数,在函数中通过列表、字典的方法修改他们。
3.2.4 变量作用域
- 局部变量
- 全局变量
Python提供了如下三个工具函数来获取指定范围内的“变量字典”: - globals() :返回全局范围内所有变量组成的“变量字典”;
- locals(): 返回当前局部范围内所有变量组成的“变量字典”;
- vars(object): 获取在指定对象范围内所有变量组成的“变量字典”,如不传入参数,其跟globals()作用一致。
全局变量默认在所有函数内都可以被访问,但是在函数中定义了与全局变量同名的变量,此时就会发生局部变量遮蔽(hide)全局变量的情形。
name='James'
def NBA():
print(name)
name='Durant'
test()
print(name)
#报错:
C:\Users\WD\PycharmProjects:
UnboundLocalError: local variable 'name' referenced before assignment
解决方法:
- 通过globals()函数访问name全局变量
- 在函数中声明全局变量
3.3 函数的高级内容
函数本身也作为一个对象,既可以用于赋值,也可以用作其他函数的参数,还可以作为其他函数的返回值。
1.使用函数变量
Python的函数也是一种值,所有的函数都时function对象,可以把函数本身赋值给变量,赋值之后程序也可以通过调用变量来调用函数。
2.使用函数作为函数形参
3.使用函数作为返回值
def get_math_fun(type):
def square(n):
return n*n #计算平方的局部函数
def cube(n):
return n*n*n #计算立方的局部函数
def factorial(n): #计算阶乘的局部函数
result=1
for i in range(2,n+1):
result*=i
return result
if type=='square':
return square
if type=='cube':
return cube
else:
return factorial #函数作为返回值
math_fn=get_math_fun('cube')
print(math_fn(5))
3.4 局部函数与lambd表达式
在上一段代码中我们引入了三个局部函数来分别计算,但是局部函数的作用域默认仅停留在其封闭函数之内,因而其作用及其有限——仅仅在程序的if语句中作为返回值使用,一旦离开函数体就失去了意义。
既然局部函数名没有太大意义,那么就考虑使用lambda表达式来简化局部函数的写法,如下:
def get_math_fun(type):
if type=='square':
return lambda n: n*n
if type=='cube':
return lambda n: n*n*n
else:
return lambda n: n*(n+1)/2
math_fn=get_math_fun('cube')
print(math_fn(5))
明显简化了很多很多。
lambd表达式的语法格式如下:
lambda[参数列表]:表达式
实际上,lambda表达式的本质就是匿名的、单行函数体的函数。虽然lambda表达式只能创建简单的函数对象,知识和函数体为单行的情形,但他依然有如下两个用途:
- 对于单行函数,使用lambda表达式省去定义函数的过程,让代码更加简洁。
- 对于不需要多次复用的函数,使用lambda表达式可以在用完之后立即释放,提高了性能。