Python函数
创建函数
在Python中,创建一个函数需要用关键字def
,参数间用逗号隔开,语法为如下
def add(a,b,c):
return a+b+c
注意函数体的缩进和函数头最后要加冒号
默认参数
在创建一个函数时,我们可以给形参默认值,在调用的时候,若没有给该形参值,则将使用默认值,但和c语言相同,所有没有默认值的形参,都必须在有默认值的的左边,例如:
def add(a,b,c=3):
print(a,b,c)
add(1,2)# 1 2 3
单星号参数
当我们不知道我们这个函数需要多少个参数时,可以使用单星号参数,它在参数前加一个*
单星号形参表示:此处接受任意多个非关键字参数,且这些参数以元组形式存储。
单星号实参表示:将可迭代对象转为多个非关键字参数。
两者可以视为互逆关系,只是单星号实参使用类型更广,而单星号形参只会作为元组
def add(a,*b,c):
for i in b:
print(i,end=' ')
print(a,c)
add(*[1,2,3,4,5],c=6)# 2 3 4 5 1 6
多星号参数
与单星号参数类似的还有多星号参数
多星号形参表示:此处接受任意多个关键字参数,这些参数以字典形式保存
多星号实参表示:将字典类型转换为多个关键字参数,再传递给函数作为参数
这两者就是简单的互逆关系,一个将关键字参数转为字典,另一个将字典转为关键字参数,例如
def fun(b, **a):
print(type(a))
for k in a:
print(k+":"+str(a[k]))
print(b)
dict1 = {"hello":1, "world":2}
fun(b="hh",**dict1, myname=3)
结果为
<class ‘dict’>
hello:1
world:2
myname:3
hh
单星号参数和多星号参数可以组成Python中的万能参数
def fun(*args, **kwargs):
pass
参数注解
在python3.5后引入的新用法,因为python函数的参数没有规定类型,所以就存在一些问题,比如:
- 由于没有规定类型,所以一些类型不对的问题很难发现
- 其他人在使用你的函数时,不知道应该传入什么参数
对函数的参数进行类型注解 ,对函数的返回值进行类型注解 ,只对函数参数做一个辅助的说明,并不对函数参数进行类型检查 , 提供给第三方工具,做代码分析,发现隐藏的bug ,函数注解的信息,保存在__annotations__
属性中
语法例子如下:
def fun(a: int, b: int)->int:
return a+b
其中:a和b后面跟着:
加一个类型。函数参数后面,冒号前面用->
指出返回类型
例如
def add(x: int, y: int)->int:
return x+y
print(add(2, 1))# 3
print(add('hello', 'world'))# helloworld
print(add.__annotations__)# {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
可见,程序并不会警告也不会报错,但程序的可读性和可维护性会提高
可以用inspect
模块来进行类型检查,详情见:https://www.cnblogs.com/s-p-l/p/10246149.html
调用函数
调用函数和c语言一样,格式为 函数名(实际参数)
在我们调用的时候,为了防止参数顺序出错等问题,可以使用关键字参数,就是在实际参数前加上形式参数的名字,这样就算交换顺序也无所谓了,注意:关键字参数必须在非关键字参数的左边,比如
def add(a,b):
print(a,b)
add(b=1,a=3)# 3 1
函数文档
函数文档是函数的一个特殊属性,它在函数体的开头,是一个字符串,在函数执行时不会执行,用于说明函数的功能
查看函数文档可以使用help(func)
方法或者直接输出__doc__
,例如
def add(a,b):
'我就是函数文档,add函数可以返回两个数相加的结果'
c = a+b
return c
print(add.__doc__)
print(-*20)
help(add)
# output:
# 我就是函数文档,add函数可以返回两个数相加的结果
# --------------------
# Help on function add in module __main__:
#
# add(a, b)
# 我就是函数文档,add函数可以返回两个数相加的结果
从结果可以看出,help其实就是美化后的函数文档
返回值
在Python中,函数可以有多个返回值,只需要在return中写多个值,中间用逗号隔开即可,相当于组成了一个元组,然后返回这个元组。
函数可以没有return,但这不意味着这个函数没有返回值,它会返回一个Nonetype类型的None
全局变量与局部变量
这一部分与c语言的类似,在函数内定义的是局部变量,在函数之外无法再次访问该局部变量,不是在函数定义的变量就是全局变量,可以在函数里被访问。
注意:如果在函数里定义了与全局变量重名的局部变量,那使用的都是局部变量,也就是说,局部变量优先级大于全局变量
如果你想要在函数中修改全局变量,可以在函数体最前面用global
对变量进行修饰,这样,在该函数中这个变量就一直是全局变量了,例如
def fun():
global x
print('a:',x)
x = 50
x = 100
fun()
print('b:',x)
# output:
# a: 100
# b: 50
在这个例子中,如果你把global x
给去掉,将会报错
还有一个类似的关键字 nonlocal
,它可以让变量不再重新定义,也就是说他会使用的是该函数的外面一层的变量,通常在内嵌函数中使用,例如
def fun():
x = 50
def fun2():
nonlocal x
print('a:',x)
return fun2()
x = 100
fun()
print('b:',x)
# output:
# a: 50
# b: 100
可见这里的fun2里输出的x是fun里定义的x,不是全局变量。
内嵌函数
python中允许在函数内定义函数,但在函数内定义的内嵌函数只能在该函数中调用,例如
def fun():
x = 50
def fun2():
print('a:',x)
fun2()
return x
x = 100
fun()
print('b:',x)
# output:
# a: 50
# b: 100
函数的闭包
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。举个例子
def fun():
x = 50
def fun2(y):
return x+y
return fun2
print(fun()(21))# 71
在这个例子中,我们可以看出,fun函数返回的是fun2的引用,所以fun()其实是一个引用,fun()(21)就相当于通过fun这个引用访问到了fun2且参数是21,这就类似于C语言的函数指针,且在fun2这个函数里,fun的临时变量x一直保留着
参考网站:https://www.cnblogs.com/s-1314-521/p/9763376.html
lambda表达式
使用 关键字lambda
可以定义一个匿名函数,只需要参数和表达式就可以了,例如
g=lambda x : 2*x
print(g(3))# 6
lambda表达式返回一个function类的对象,它没有名字,当一个函数使用只使用一次时可以考虑使用,常与filter和map搭配
9.过滤器filter(function,sequence)
有两个参数,function是一个自定义的函数,只能有一个参数,返回值为布尔类型。sequence是一个序列(列表,元组或字符串)。
它可以筛选出序列中满足函数的条件的序列,返回一个迭代器类型,例如,筛选出0-10之间所有的奇数,示例如下。
print(list(filter(lambda x:x%2,range(10))))# [1, 3, 5, 7, 9]
映射器map(function,iterable1,…)
function中参数值可以是一个,也可以是多个;后面的iterable代表function运算中的参数值,有几个参数值就传入几个iterable
它可以依次取出iterable的值,带入function中,将结果保存在序列中,举个例子。
print(list(map(lambda x,y:x+y,range(0,10),range(1,11))))
结果为
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
注意:map中如果传入的序列长度不一,会依据最短的序列计算
Python参数传递的机制
与Java类似,是引用传递,将引用复制进行传递