一、函数
当我们在编写程序时。可能会遇到某些功能相似的代码。此时为了减少代码冗余,我们可以使用将功能相似的代码写成一个函数,并在适当的位置调用。
二、函数定义
引入一个关键字
def
用于定义一个函数
它必须后跟
函数名称
和
带括号的形式参数列表
。
构成函数体的语句从下一行开始,并且
必须缩进
。
函数体的第一个语句可以(可选的)是字符串文字; 它是函数文档字符串, 用于解释函数的功能, 及参数和返回值的含义
函数的 执行 会引入一个用于
函数局部变量
的新符号表。 更确切地说,
函数中所有的变量赋值都将存储在局部符号表
中;
变量引用会首先在局部符号表中查找
,
然后是
外层函数的局部符号表
,
再然后是
全局符号表
,
最后是
内置名称的符号表
语法规则
def function_name(形参列表):
"""函数文档""" [可选]
函数执行的代码
return 返回值
函数被调用时,
实际参数
会被引入
被调用函数的本地符号表
中;
实参是通过
按值调用
传递的
其中
值
始终是
对象引用
: 即使对象的
id
而
不是对象的值
函数调用是通过
函数名(形参列表)
形式调用
当一个函数调用另外一个函数时,将会为该调用创建一个新的本地符号表。
即使没有
return
语句的函数也会返回一个值,这个值称为
None
(它是内置名称)
示例程序
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=" ")
a, b = b, a+b
print()
fib(10) # 函数调用
def fib2(n):
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
print(fib2(10))
三、函数的参数形式
上面示例程序中的函数参数是
必备参数形式
. 即在调用函数时, 必须传入参数到函数中. 否则会报错.
3.1 空参数形式
函数不需要参数就能被调用.
def printf():
print("hello world")
3.2 参数默认值
对一个或多个参数指定一个默认值。这样创建的函数,可以用比定义时允许的
更少
的参数调用.
def function_name(agr1=value1,arg2=value2):
函数内执行代码
默认值是在函数定义处计算
i = 10
def print_i(arg=i):
print(arg) # 输出的是10
print(i) # 输出6
i = 6
print_i()
默认值只会执行一次
def fun(a, L=[]):
L.append(a)
return L
print(fun(1)) # 输出[1]
print(fun(2)) # 输出[1, 2]
print(fun(3)) # 输出[1, 2, 3]
如果你不想要在后续调用之间 共享默认值, 函数进行如下定义:
def fun(a, L=None):
if L is None:
L = []
L.append(a)
return L
print(fun(1)) # 输出[1]
print(fun(2)) # 输出[2]
print(fun(3)) # 输出[3]
3.3 不定长参数形式
有时候函数需要很多的参数, 如果全部显示写出来会显得函数定义臃肿. 可以使用不定长参数来定义函数
语法如下
def function_name(*args, **kwargs):
函数内执行代码
*args
当以变量形式直接传入多个参数时,会被
*args
接收并打包成元组的形式存在args中传入函数内。
**kwargs
当以映射(默认参数)的形式传入参数时,会被
**kwargs
接收并打包成字典形式存在kwargs中传入函数内
3.4 特殊参数
/
*
默认情况下,函数的参数传递形式可以是位置参数或是显式的关键字参数。 为了确保
可读性和运行效率
,限制允许的参数传递形式是有意义的,这样开发者只需查看函数定义即可确定参数项是仅按位置、按位置也按关键字,还是仅按关键字传递。
函数的定义看起来可以像是这样:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
如果函数定义中未使用
/
和
*
,则参数可以按位置或按关键字传递给函数。
如果使用了
/
, 则
/
之前的参数
只能通过位置传参
; 之后的参数
可以通过位置传参, 也可以同关键字传参
如果使用了
*
, 则
*
之后的参数
必须以关键字传参
3.5 解包参数
通过
*
操作符来将列表或元组解包用于位置参数传递
通过
**
操作符来将字典解包用于关键字参数的传递
四、函数的标注
针对函数参数和返回值
类型的说明
语法格式如下
def function_name(arg1: 类型, arg2: 类型 = "默认值")-> 类型:
函数执行的代码
五、闭包
闭包是指在
函数内部嵌套一个函数
,可由外层函数返回内层函数的函数名。
def func():
def text():
print("hello world")
return text
text = func() # 调用外层函数获取内层函数函数名
text() # 调用内层函数。
闭包是函数里面嵌套函数,外层函数返回里层函数,这种情况称之为闭包
闭包是概念,不是某种函数类型,和递归的概念类似,就是种特殊的函数调用
闭包可以得到外层函数的局部变量,是函数内部和函数外部沟通的桥梁
六、变量的作用域
函数内部可以查看函数外部的变量, 但是不能修改函数外部变量.
函数内部变量不能在函数外部使用.
全局变量
可以在程序任意位置访问的的变量称为全局变量.
局部变量
只能在特定位置访问的变量称为局部变量. 比如函数内的定义的变量, 控制语句中定义的变量.
6.1 全局变量的使用
python中函数内部是不能修改函数外部的变量的. 要使用关键字
global
在函数内部声明全局变量, 才能对全局变量进行修改
global_int = 12
def func():
global global_int
global_int += 1
print('函数内部',global_int)
func()
print('函数外部',global_int)
6.2 局部变量的使用
定义在函数内部的变量. 如果内层函数要修改外层函数的变量使用关键字
nonlocal
声明局部变量, 这样才能在内层函数修改外层函数的变量
def glo():
test_non = 34
print("外部函数", test_non)
def test():
nonlocal test_non
test_non += 1
print('内部测试函数', test_non)
return test
glo()()