1、函数
(1)基本知识
-
函数是对功能的封装
-
语法
def function_name([parameters]): function_body
-
返回值
- 如果没有return,或者return后面不跟数据,返回None
- return后的语句不执行,即终止函数
- return可以返回多个值,即
return value1, value2, ...
- 多个返回值返回的是一个元组
-
参数:形参、实参和传参
- 形参:函数声明时的未知的变量
- 位置参数
- 默认值参数:如
def fuc(argu1, argu2 = None)
- 当argu2没有实参时,默认argu2=None
- 注意:当默认值参数可变时(列表、指定、集合),默认值变量不会随函数结束而消亡
- 动态参数:即不定参数
- 实参:函数调用的时候给的具体的值
- 位置参数:按照形参顺序传递实参
- 关键字参数:按照形参名字传递实参,与位置无关
- 混合参数:位置参数和关键字参数一起使用,先位置参数,后关键字参数(必须先位置参数)
- 传参:过程
- 形参:函数声明时的未知的变量
-
例子
In [30]: def fuc(para1, para2, para3=None): ...: print(para1) ...: print(para2) ...: print(para3) ...: In [31]: fuc(1, 2) 1 2 None In [32]: fuc(1, 2, 3) 1 2 3 In [33]: fuc(para3=1, para2=2, para1=3) 3 2 1
def fuc(para1, para2, para3=None)
- para1、para2、para3就是形参
- 其中para1和para2为位置参数,是有严格的顺序的
- para3为默认值参数,即不给para3传值时它有默认值
fuc(1, 2, 3)
- 1、2、3就是实参,是具体传递的值
- 这里三个实参都是位置参数,即按顺序给形参赋值
fuc(para3=1, para2=2, para1=3)
- 这里的1、2、3就是关键字参数,与位置无关,直接按形参的名字赋值
(2)参数传递
-
动态传参
-
def function(*argument_name)
*表示动态传参(位置参数),函数接收的数据类型是元组- 注意:使用这种动态传参时要注意位置参数,合理顺序是先位置参数,再动态参数,最后默认值参数
(因为默认值要生效就不能往形参传值) def fuc1(name, *food)
def fuc2(*food, name)
fuc1和fuc2函数体相同fuc1(a, b, c, d)
和fuc2(a, b, c, d)
效果不同,因为对于fuc2,food把a、b、c、d都接收了
In [34]: def f1(a, *args): ...: print(a) ...: print(args) ...: In [35]: def f2(*args, a): ...: print(a) ...: print(args) ...: In [36]: f1(1, 2, 3) 1 (2, 3) In [37]: f2(1, 2, 3) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-37-f8cc322696a9> in <module>() ----> 1 f2(1, 2, 3) TypeError: f2() missing 1 required keyword-only argument: 'a'
- 可以看到使用f2时报错了,因为形参args将所有实参都吸收了
- 由此我们知道
*args
参数一定要放到位置参数后面
- 注意:使用这种动态传参时要注意位置参数,合理顺序是先位置参数,再动态参数,最后默认值参数
-
def function(**argument_name)
**表示动态传参(关键字参数),函数接收的数据类型是字典In [38]: def fuc(a1=None, **kwargs): ...: print(a1) ...: print(kwargs) ...: In [39]: fuc(name='aaa', age=20) None {'name': 'aaa', 'age': 20} In [40]: fuc(100, name='aaa', age=20) 100 {'name': 'aaa', 'age': 20} In [41]: fuc(name='aaa', age=20, 100) File "<ipython-input-41-86542b6e5b0a>", line 1 fuc(name='aaa', age=20, 100) ^ SyntaxError: positional argument follows keyword argument
- 可以看到若实参使用关键字参数,且形参中没有定义,则这些实参会被放到一个字典里
- 从上例中我们也可以得知
**kwargs
应该放在位置参数后面
-
(3)参数合理顺序
-
参数合理顺序应该是:
位置参数,*args,默认值参数,**kwargs(key word)
-
例子如下
In [42]: def fuc(a1, a2, *args, a3=None, a4=None, **kwargs): ...: print(a1) ...: print(a2) ...: print(args) ...: print(a3) ...: print(a4) ...: print(kwargs) ...: In [43]: fuc(100, 200, 300, 400) # 100->a1, 200->a2, 300和400->args 100 200 (300, 400) None None {} In [44]: fuc(100, 200, a3=300, a4=400, a5=500, a6=600) # 100->a1, 200->a2, 300->a3, 400->a4, a5=500和a6=600->kwargs 100 200 () 300 400 {'a5': 500, 'a6': 600}
(4)函数注释
-
函数的整体注释可以这样写
In [45]: def fuc(): ...: ''' ...: 函数名称:fuc ...: 函数功能:··· ...: 入口参数:··· ...: 出口参数:··· ...: ''' ...: pass ...: ...: In [46]: print(fuc.__doc__) 函数名称:fuc 函数功能:··· 入口参数:··· 出口参数:···
(5)聚合(形参)
- 接收所有参数:
def fuc(*args, **kwargs)
*args,**kwargs
相当于一个聚合的作用
(6)打散(实参)
-
打散是用的
*args
的特性,例子如下In [52]: def fuc(*para): ...: print(para) ...: In [53]: l = [1, 2, 3] In [54]: fuc(l) ([1, 2, 3],) In [55]: fuc(l[0], l[1]) (1, 2) In [56]: fuc(l[0], l[1], l[2]) (1, 2, 3)
-
可以打散的类型有
list、tuple、string、set、dictory
2、作用域
-
名称空间:
- 1、内置名称空间 2、全局名称空间 3、局部名称空间
- 1->2->3(python解释器运行顺序)
-
作用域命名空间
- 全局作用域:内置名称空间、全局名称空间
- 局部作用域:局部名称空间
globals()
查看全局作用域的内容locals()
查看当前的作用域的内容
-
函数的嵌套:
- 函数的定义可以嵌套
- 访问函数时要注意作用域
-
global
和nonlocal
global value_name
可以把全局中的变量引入到函数内部或者在函数内部中创建一个全局变量nonlocal value_name
从当前作用域往外层(全局作用域)方向寻找value_name,- 注意,不找全局作用域的变量,且只找离当前作用域最近的一层
-
例子1
In [11]: l = [1, 2, 4] In [12]: def f1(): ...: print(l) ...: In [13]: f1() [1, 2, 4] In [14]: num = 100 In [15]: def f2(): ...: print(num) ...: In [16]: f2() 100 In [17]: def f3(): ...: a = 'hhhh' ...: In [18]: print(a) --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-18-bca0e2660b9f> in <module>() ----> 1 print(a) NameError: name 'a' is not defined
- 局部作用域内可以访问全局作用域里的变量
- 但是全局作用域内不可以访问局部作用域里的变量
-
例子2
In [28]: num = 100 In [29]: def fuc(): ...: num = 200 ...: print(num) ...: In [30]: fuc() 200 In [31]: print(num) 100 In [32]: def fuc2(): ...: global num ...: num = 300 ...: In [33]: fuc2() In [34]: print(num) 300
- 在局部作用域内是无法修改全局作用域里的变量的
- 若要修改,必须在局部作用域内将变量声明为全局变量
- 函数被执行后,变量才被修改(若不执行函数,则只是创建了函数,函数里的语句并未执行)