目录
Python函数的基本格式
Python函数的定义与其他语言类似,但是Python的函数体没有大括号所包围,所以函数体的缩进要严格。
def 函数名(参数1,参数2,...,参数n):
函数体代码块
·
·
·
·
return 返回值
Python中的函数也是一个对象,将可执行的代码块存在内存中,这些代码块不会立即执行,定义时只检查语法错误,只在调用函数时才会执行。Python中函数的定义语法非常灵活,但是灵活所带来的问题就是容易出错,尤其体现在参数的设置和传递上。
由于Python中定义的变量的类型是动态类型,所以函数中的参数也不会指定变量类型,相传什么就传什么。在函数体代码块中使用参数时才会检查其类型。
Python函数的传参
形式参数
Python函数的形式参数与c/c++中的类似,只存在于函数中,相当于在函数中定义了一个局部变量,函数结束后这个变量就被销毁了,可以设置默认值。
实际参数
实际参数的传递有两种方式,一种是按位置传参,就是按形参的定义顺序来传参。例如:
>>> def fun1(a,b,c):
... print(a)
... print(b)
... print(c)
...
>>> fun1(1,2,3)
1
2
3
另一种是按关键字传参,即调用函数时指明形式参数的值。例如:
>>> def fun1(a,b):
... print(a)
... print(b)
...
>>> fun1(b=1,a=2)
2
1
也可以混合使用,但是要将位置实参写到前面。例如:
>>> def fun1(a,b,c):
... print(a)
... print(b)
... print(c)
...
>>> fun1(1,c=3,b=2)
1
2
3
不定长参数
形参的设置还有一种不定长参数,即可以传递未知数量的参数,类型也是任意的,但是不能接受关键字传值。写法就是在形参之前加“*”即可,而且形参列表中只能有一个带“*”的形参,否则会引起歧义。例如:
>>> def fun(*a):
... print(a)
...
>>> fun(1,2,3,4,5)
(1, 2, 3, 4, 5)
不定长参数可以和其他参数配合使用,此时带星号参数需要写到形参列表的末尾。如果不写到末尾的话,也可以将带星号的参数后面的所有参数使用关键字传值。例如:
>>> def fun(a,b,*c,d):
... print(c)
... print(d)
...
>>> fun(1,2,3,4,5,d=6)
# 1给了a,2给了b,3 4 5给了c
(3, 4, 5)
6
实参的值
有些类型的实参的值是可以在函数中修改的,例如:list、dictionary、set。但是有些不可以,例如:tuple、number、string等。例如:
#list可以被修改
>>> def fun(a):
... a[0]=2
...
>>> b=[1,2,3]
>>> fun(b)
>>> print(b)
[2, 2, 3]
# 数字不可以被修改
>>> def fun(a):
... a=10
...
>>> b=5
>>> fun(b)
>>> print(b)
5
函数的拆包
如果想给函数传递一个list或者set,可以使用函数的拆包调用。即在传递实参时,在参数名之前加上“*”。例如:
>>> def fun(a,b,c):
... print(a)
... print(b)
... print(c)
...
>>> d=[1,2,3]
>>> fun(*d)
1
2
3
>>> d={"a":1,"b":2,"c":3}
>>> fun(**d)
1
2
3
Python函数的文档说明
如果想给这个函数添加一些注释,说明参数的意义,函数的作用,返回值的意义等,可以在函数中使用三个单引号的注释形式来写。然后使用help函数来显示这些注释。例如:
作用域
Python中的作用域分为全局作用域和函数作用域,与c/c++中的非常类似,可以类比着学习。所有函数之外的作用域都是全局作用域,全局作用域在程序执行时创建,在程序结束时销毁。而函数作用域在函数被调用时创建,函数结束时销毁,函数每调用一次就会产生一个新的函数作用域。在使用一个变量时,会优先在当前的作用域中查找。
命名空间
Python中的命名空间存储了当前作用域中所有的对象和对象所对应的值或地址。本质上是一个字典。locals函数可以获取当前作用域的命名空间,globals函数可以获取全局作用域的命名空间。例如:
>>> a=10
>>> b=15
>>> c=20
>>> def fun():
... a=1
... b=2
... c=3
... local_a=locals()
... global_a=globals()
... print(local_a,type(local_a))
... print(global_a,type(global_a))
...
>>> fun()
{'c': 3, 'b': 2, 'a': 1} <class 'dict'>
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <cl
ass '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {
}, '__builtins__': <module 'builtins' (built-in)>, 'fun1': <function fun1 at 0x0
1EC4738>, 'fun': <function fun at 0x01EC4780>, 'b': 15, 'd': {'a': 1, 'b': 2, 'c
': 3}, 'a': 10, 'c': 20} <class 'dict'>
在全局作用域中还有程序自带的一些对象,例如__name__等。
闭包
闭包在好多地方都有定义,Python中的闭包是个较为复杂的概念,我在另一篇中做了详细解释: