Python教程 - 函数
当程序变得越来越复杂时,就需要将一些重复或具有特定定义的代码片段拆分成易于管理的小程序,这些小程序被称为“函数”。函数是一种有名称且独立的程序片段,可以接受任何类型的参数,并在处理完成后输出任何类型的结果。
定义函数
在 Python 中,使用def
来定义一个函数,函数的命名规则与变量相同(可以使用字母、数字或下划线;只能以字母或下划线开头)。以下是名为hello
函数的基本结构:
def 后方通常会放上函数名称 (名称不能和变数名称重复)、输入参数的小括号,后方再加上一个冒号,缩进里的代码就属于这个函数。
def hello():
print('hello')
hello() # 执行函数,打印出 hello
注意,必须“先定义函数,再执行函数”,否则执行时会发生错误。下面的代码将执行函数放在定义函数之前,执行时就会发生错误。
hello()
def hello():
print('hello') # 发生错误 name 'hello' is not defined
函数参数
函数可以接收“参数”,在执行函数时传入这些参数指定的数值(实参),就能让函数根据不同参数的内容,计算出不同的结果。
下面的hello
函数有一个msg
参数,目的是打印出传入的参数,执行函数时如果传入的内容不同,就会有不同的结果。
def hello(msg):
print(msg)
hello('hello') # hello
hello('good morning') # good morning
一个函数可以声明多个参数,下面的hello
函数具有x
和y
两个参数,根据不同的参数数值进行计算,最后打印出两个参数的加和结果。
注意,执行函数时,会按照“顺序”处理多个参数,例如函数参数顺序如果是
(x,y)
,执行时填入(1,2)
,x
就会是 1,y
就会是 2。
def hello(x,y):
z = x + y
print(z)
hello(1,2) # 3
hello(5,6) # 11
参数默认值
函数的参数可以“指定默认值”,如果在执行函数时没有提供参数数值,参数就会自动带入默认值执行。下面的程序设置参数y
的默认值为 10,如果在执行时没有提供参数y
的数值,y
就会使用 10 带入计算。
def hello(x,y=10):
z = x + y
print(z)
hello(1,2) # 3
hello(5) # 15
关键字参数
函数除了通过“顺序”(位置)指定参数外,也可以使用“关键字参数”(指定的名称)来设置特定的参数内容(实参表示提供给参数的数值)。
下面的程序里,hello
函数有name
和age
两个参数,如果在执行函数时提供的数值顺序不同,产生的结果就会不同。如果额外使用关键字参数,即使提供的顺序不同,仍然会是正确的结果。
def hello(name, age):
msg = f'{name} is {age} years old'
print(msg)
hello('anna',18) # anna is 18 years old
hello(18,'anna') # 18 is anna years old (因为18和anna对调,所以结果就会对调)
hello(age=18,name='anna') # anna is 18 years old (使用关键字参数,结果就会是正确的)
此外,在定义函数时也可以赋予关键字参数内容,执行后即使没有提供该参数的数值,仍然会套用默认值。以下面的程序为例,如果不指定start
和end
,就会默认使用 0 和 3。
def test(a, start=0, end=3):
for i in a[start:end]:
print(i)
b = [1,2,3,4,5]
test(b, start=2, end=len(b)) # 3 4 5
test(b) # 1 2 3
函数返回值
函数除了可以传入参数,也可以使用return
返回程序运算后的结果。返回的结果不限类型,可以是数字、字符串、列表、元组等。下面的代码,执行函数a
之后,函数会计算并返回x + y * 2
的结果,最后将结果赋值给变量b
和c
。
def a(x, y):
result = x + y*2
return result
b = a(1,2)
c = a(2,3)
print(b) # 5
print(c) # 8
当函数执行过程中遇到return
时,就会“中止函数”并返回结果。以下面的程序为例,当x=1
(每次result
增加 1)的时候,会触发result == 5
的逻辑判断,就会中止函数(函数内的 while 循环也就跟着停止),并返回 5 的结果。当x=2
(每次result
增加 2)的时候,不会触发result == 5
的逻辑判断,就会执行完 while 循环,最后返回 10 的结果。
def a(x):
result = 0
while result < 10:
result = result + x
if result==5:
return result
return result
b = a(1)
c = a(2)
print(b) # 5
print(c) # 10
函数也可以返回多个结果,如果返回多个结果,可以赋值给“同样数量”的变量(不同数量会发生错误)。
def test(x, y, z):
return x+1, y+1, z+1
a, b, c = test(1, 2, 3) # 赋值给“同样数量”的变量
print(a) # 2
print(b) # 3
print(c) # 4
函数返回的多个结果也可以只赋值给一个变量,这时就会将多个结果变成一个元组。
def test(x, y, z):
return x+1, y+1, z+1
a = test(1, 2, 3)
print(a) # (2, 3, 4)
函数内的函数
在一个函数里也可以放入另外的函数,形成函数内的函数,但函数内的函数只能在函数里使用。下面的代码,在hello
函数里,建立了h1
和h2
的内部函数,根据不同的参数执行不同的函数,如果在外部执行内部函数,就会发生错误。
def hello(n, msg):
def h1(): # 内部函数
return msg
def h2(): # 内部函数
return msg*2
if n == 1:
print(h1())
if n == 2:
print(h2())
hello(1, 'ok') # ok
hello(2, 'ok') # okok
print(h2()) # 发生错误 name 'h2' is not defined
函数内的变量
如果放在函数里的变量,没有经过 global 的声明,就会成为“局部变量”(更多参考:全局变量、局部变量)。
a = 123 # 全局变量 a
b = 123 # 全局变量 b
def hello(msg):
a = msg # 局部变量 a,更改局部变量不影响全局变量
print(a)
global b # 声明变量 b 是使用全局变量 b,更改等于更改全局变量
b = msg
hello(456) # 456
print(a) # 123
print(b) # 456 被更改为 456
如果函数里又有其他函数,需要使用局部变量,可以将变量声明为 nonlocal 的自由变量,就能自由地在函数里使用。下面的代码有声明 a 为自由变量,所以执行后会正常运作,但是因为 b 没有声明为自由变量,所以使用时就会发生错误。
def hello(msg):
a = 123
b = 123
def h1():
nonlocal a # 声明 a 为自由变量
a = a + msg
print(a)
def h2():
b = b + msg
print(b)
h1() # 579
h2() # 发生错误 local variable 'b' referenced before assignment
hello(456)
*args
和**kwargs
运算符
在 Python 中,*args
和 **kwargs
是两种特殊的语法结构,用来使函数能够接收可变数量的参数。args
和kwargs
的只是变量名称,可以自由更换,重点在于前方的一个星号与两个星号,但是约定俗成使用这两个名称。它们增强了函数的灵活性,允许你在不知道具体参数数量的情况下编写代码。下面是它们的详细解释:
*args
如果将函数的参数设置为带有args
(一个星号*)运算符的参数,则可以传递任意数量的位置参数,传入的所有位置参数都会被打包成元组。这样,函数就可以处理不同数量的参数。
def test(*args):
print(args)
test(1,2,3,'a','b','c')
# (1,2,3,'a','b','c')
**kwargs
如果把函数的参数定义带有kwargs
(两个星号**)运算符的参数,意味着该函数可以接受任意数量的关键字参数。所有传递的关键字参数打包成一个字典(dictionary)并传递给函数,其中关键字作为字典的键,对应的值作为字典的值。
def test(**kwargs):
print(kwargs)
test(name='oxxo',age=18,like='book')
# {'name': 'oxxo', 'age': 18, 'like': 'book'}
结合使用
如果 *args
、**kwargs
同时出现,则会根据输入的内容,分别套用 *args
或 *kwargs
的规则,比如下方的 a 函数使用参数时,传入的 123,456
属于 *args
打包为一个元组,x=1, y=2, z=3
属于 **kwargs
打包为一个字典。
def a(*args, **kwargs):
print(args)
print(kwargs)
a(123, 456, x=1, y=2, z=3)
# (123, 456)
# {'x': 1, 'y': 2, 'z': 3}
需要注意的是在传递参数时“位置参数”和“关键字参数”不能交叉传递。
def a(*args, **kwargs):
print(args)
print(kwargs)
a(123, 456, x=1, y=2, z=3, 789) # 位置参数的传递一定要在关键字参数之前
# a(123, 456, x=1, y=2, z=3,789)
# ^
# SyntaxError: positional argument follows keyword argument
同时使用时要注意的是函数定义入参时*args
、**kwargs
的顺序是固定的只能是*args
在前**kwargs
在后,如颠倒顺序就会出错。
def b(**kwargs, *args): # 顺序颠倒,编译失败
print(args)
print(kwargs)
# def b(**kwargs,*args):
# ^
# SyntaxError: invalid syntax
使用 pass
如果想定义一个什么事都不做的空函数,可以使用 pass 语句:
def test():
pass
pass 除了可以应用在函数,也可以使用在判断式里,作为一个占位符使用 (不会执行任何事情,但必须出现的程序代码)。
a = int(input('>'))
if a>10:
pass # 如果输入的数字大于 10,不做任何事情
else:
print(a)
转载自:https://juejin.cn/post/7366515669352005647