概述
在Python中,使用关键字**def定义函数。不需要为函数指定具体的返回类型。
关键字def**后跟函数名和一对小括号,括号中可以带形参列表(参数之间以逗号分隔),也可以为空不带任何形参。
函数的定义
def myFunc():
print('hello, world')
函数调用
def myFunc():
print('hello, world')
myFunc()
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
hello, world
Process finished with exit code 0
多种形式的函数定义
具有形参的函数定义
def myFunc(name, age):
print('hello, my name is : ', name , ", years old is : " , age)
myFunc('wzc', 1000)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
hello, my name is : wzc , years old is : 1000
Process finished with exit code 0
形参具有默认值的函数定义
第一个具有默认值的形参,其后的形参也必须有默认值,否则会出错;第一个具有默认值的形参,其前边可以有形参,也可以没有(如下面的args参数)
def myFunc(args, name='bruce', age=10):
print('hello, my name is : ', name , ", years old is : " , age)
不指定实参,默认全部使用形参默认值
def myFunc(name='bruce', age=10):
print('hello, my name is : ', name , ", years old is : " , age)
myFunc()
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
hello, my name is : bruce , years old is : 10
Process finished with exit code 0
指定部分实参,另一部分使用形参默认值
def myFunc(name='bruce', age=10):
print('hello, my name is : ', name , ", years old is : " , age)
myFunc('Jhone')
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
hello, my name is : Jhone , years old is : 10
Process finished with exit code 0
给形参全部指定实参,不使用形参默认值
def myFunc(name='bruce', age=10):
print('hello, my name is : ', name , ", years old is : " , age)
myFunc('wzc', 1000)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
hello, my name is : wzc , years old is : 1000
Process finished with exit code 0
通过给形参名赋值的方式传参
def myFunc(name='bruce', age=10):
print('hello, my name is : ', name , ", years old is : " , age)
myFunc(name='Jack')
myFunc(age = 18, name='Jack') # 参数名的顺序和定义的顺序一致
myFunc(name='Jack', age = 24) # 参数名的顺序和定义的顺序不一致
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
hello, my name is : Jack , years old is : 10
hello, my name is : Jack , years old is : 18
hello, my name is : Jack , years old is : 24
Process finished with exit code 0
关键字参数的函数定义
可以简单理解**关键字参数**的含义: 将其参数名和参数值当作是字典的 键-值对,即具有默认值的形参名看作是字典的键。
关键字参数之前可以有也可以没有不带默认值的形参(一个或者多个,如果有默认值,那么它就属于关键字参数了,),这种参数叫作位置参数
关键字参数个数确定的函数形式
def myFunc(args, name='bruce', age=10, country='china', province='henan'):
print('args' , args)
print('hello, my name is : ', name , ", years old is : " , age)
print('from ', country, ',', province)
参数args就叫作位置参数,其后的其他“”键-值“”对参数叫作关键字参数。
注意: 如果一个函数的参数列表同时有位置参数和关键字参数,则关键字参数必须放在位置参数后面
在函数调用进行值传递时,如果位置参数想以任意顺序传参,在位置参数和关键字参数都需要通过“键=值”的形式传参,否则会出错,如下出错的情况
def myFunc(args, name='bruce', age=10, country='china', province='henan'):
print('args' , args)
print('hello, my name is : ', name , ", years old is : " , age)
print('from ', country, ',', province)
myFunc(100, args=1000)
出错输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
Traceback (most recent call last):
File "E:/Python3/Exercise/venv/02.py", line 10, in <module>
myFunc(100, args=1000)
TypeError: myFunc() got multiple values for argument 'args'
Process finished with exit code 1
正确调用形式:
def myFunc(args, name='bruce', age=10, country='china', province='henan'):
print('args' , args)
print('hello, my name is : ', name , ", years old is : " , age)
print('from ', country, ',', province)
myFunc(age = 100, args=1000)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
args 1000
hello, my name is : bruce , years old is : 100
from china , henan
Process finished with exit code 0
关键字参数个数不确定的函数形式(**kwarg)
这种形式的关键字参数(**kwarg),该函数会通过它接收一个字典参数。
但是不能真去传递一个字典数据类型,否则也会将传入的字典类型数据当作位置餐护士,会出错,如下所示
关键字参数错误传递方式:
def myFunc(args, **kwargs):
print('args' , args)
for k in kwargs:
print('key = ', k)
dsk = {'A':65, 'B':66, 'C':67, 'D':68}
myFunc(2, dsk)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
Traceback (most recent call last):
File "E:/Python3/Exercise/venv/02.py", line 10, in <module>
myFunc(2, dsk)
TypeError: myFunc() takes 1 positional argument but 2 were given
Process finished with exit code 1
正确的传递关键字参数是以**键=值**的形式传参,如
def myFunc(args, **kwargs):
print('args' , args)
for k in kwargs:
print('key = ', k, 'value = ', kwargs.get(k))
myFunc(2, A=65, B=66, C=67, D=68)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
args 2
key = A value = 65
key = B value = 66
key = C value = 67
key = D value = 68
Process finished with exit code 0
任意数据类型传参
函数的参数可以是任何数据类型(字符串、数字、列表、字典等),并且在函数内其将被视为相同数据类型。
列表传参
以列表传参,则传递到函数内,该参数仍然是列表。
def myFunc(args):
for x in args:
print(x)
lst = [1, 2, 3, 'a', 'b', 'c']
myFunc(lst)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
1
2
3
a
b
c
Process finished with exit code 0
元组传参
def myFunc(args):
i = 0
while i < len(args):
print(args[i])
i += 1
myFunc((1, 2, 3, 5, 'a', 'b'))
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
1
2
3
5
a
b
Process finished with exit code 0
字典传参
def myFunc(args):
for k in args:
print('key = ', k, 'value = ', args[k])
myFunc({'a':1, 'b':2, 'c':3, 'd':5})
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
key = a value = 1
key = b value = 2
key = c value = 3
key = d value = 5
Process finished with exit code 0
注意: 具有默认值的参数,如果参数是可变对象,如**列表、字典等**,则默认值参数的内存空间只会分配一次(可以理解为C语言中的常量)。
如,下面的默认值是一个空列表的参数,连续调用之后,会将它每次传递的参数都会放在第一次调用时创建的列表空间中:
def myFunc(args, lst = []):
lst.append(args)
return lst
print(myFunc(1))
print(myFunc(2))
print(myFunc(3))
print(myFunc(4))
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
Process finished with exit code 0
如,下面的默认值是一个空字典的参数,连续调用之后,会将它每次传递的参数都会放在第一次调用时创建的字典空间中:
def myFunc(args, dsk={}):
for k in args:
dsk[k] = args[k]
return dsk
dsk = myFunc({'a':1})
for i in dsk:
print('key = ', i, 'value = ', dsk[i])
print('*' * 50)
dsk = myFunc({'b':2})
for i in dsk:
print('key = ', i, 'value = ', dsk[i])
print('*' * 50)
dsk = myFunc({'c':3})
for i in dsk:
print('key = ', i, 'value = ', dsk[i])
print('*' * 50)
dsk = myFunc({'d':5})
for i in dsk:
print('key = ', i, 'value = ', dsk[i])
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
key = a value = 1
**************************************************
key = a value = 1
key = b value = 2
**************************************************
key = a value = 1
key = b value = 2
key = c value = 3
**************************************************
key = a value = 1
key = b value = 2
key = c value = 3
key = d value = 5
Process finished with exit code 0
任意数量的参数传参(*args)
如果不知道将传递给函数的参数有多少,在参数名前加 *,则表示有任意多的参数。
在函数内部,是将其作为元组数据来接收的。
传递的参数可以是任意数据类型(字符串,列表,字典,元组等),个数任意。
def myFunc(*args):
print(args)
# 传递一个字符串
myFunc('hello, world')
print('*' * 50)
# 只传递一个元组参数
myFunc((1,2,3,4))
# 传递一个列表
myFunc(['a', 'b', 'c'])
print('*' * 50)
# 传递一个字典
myFunc({'A':65, 'B':66})
print('*' * 50)
# 同时传递多个参数
myFunc(12, 34.0, 'hello, world', (1,2,3,4), ['a', 'b', 'c'], {'A':65, 'B':66})
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
('hello, world',)
**************************************************
((1, 2, 3, 4),)
(['a', 'b', 'c'],)
**************************************************
({'A': 65, 'B': 66},)
**************************************************
(12, 34.0, 'hello, world', (1, 2, 3, 4), ['a', 'b', 'c'], {'A': 65, 'B': 66})
Process finished with exit code 0
*args和**kwargs同时作为函数的参数
任意数量的参数 *args必须在关键字参数 **kwargs之前。
def myFunc(a, *args, **kwargs):
print(a)
print(args)
print(kwargs)
myFunc(10, 'hello', 'world', name='wzc', age='18', sex='male')
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
10
('hello', 'world')
{'name': 'wzc', 'age': '18', 'sex': 'male'}
Process finished with exit code 0
具有特殊参数(*或者/)的函数
默认情况下,可以将参数分为两类: 1. 位置参数 ; 2. 显式的关键字参数(**kwarg)
为了确保可读性(看一眼函数定义原型就知道参数是属于哪一类的)和运行效率,可以通过给函数增加可选的参数 * 或者 / 显示的限制传递的参数类型就可以达到这个目的。
具有特殊参数的函数定义,可以像如下的定义方式
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
仅限位置参数的函数定义
仅限位置参数的函数定义,其位置参数必须位于特殊参数 / 之前。
特殊参数 ==/==被用来分割仅限位置形参和其他形参,也就是说它后面的形参可以是位置参数,也可位置形参,也可以是关键形参,或者是仅限制关键字形参
def specArgsFunc(arg, /):
print('这是一个仅限位置参数的函数, 位置参数的值为: ', arg)
specArgsFunc(10)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
这是一个仅限位置参数的函数, 位置参数的值为: 10
Process finished with exit code 0
如果传递关键字参数,会报错
def specArgsFunc(arg, /):
print('这是一个仅限位置参数的函数, 位置参数的值为: ', arg)
specArgsFunc(a=100)
出错信息:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
Traceback (most recent call last):
File "E:/Python3/Exercise/venv/02.py", line 8, in <module>
specArgsFunc(a=100)
TypeError: specArgsFunc() got an unexpected keyword argument 'a'
Process finished with exit code 1
仅限关键字参数的函数定义
仅限关键字参数的函数定义,其函数中第一个仅限关键字参数之前必须是一个特殊参数 * ,也就是说仅限关键字形参必须在*号后面
特殊参数*被用来分割其他形参和仅限关键字形参*后面的关键字参数可以是一个或者多个 。
def specArgsFunc(*, arg, arg2, arg3):
print('这是一个仅限关键字参数的函数, 关键字参数的值为: ', arg, arg2, arg3)
specArgsFunc(arg= 100, arg2=101,arg3=102)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
这是一个仅限关键字参数的函数, 关键字参数的值为: 100 101 102
Process finished with exit code 0
即限位置参数也限关键字参数的函数定义
def specArgsFunc(arg0, /, *, arg, arg2, arg3):
print('仅限位置参数的值为:',arg0, '仅限关键字参数的值为: ', arg, arg2, arg3)
specArgsFunc(10, arg= 100, arg2=101,arg3=102)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
仅限位置参数的值为: 10 仅限关键字参数的值为: 100 101 102
Process finished with exit code 0
递归函数
Python 也接受函数递归, 函数调用自身。
def tri_recursion(k):
if(k>0):
result = k+tri_recursion(k-1)
print(result)
else:
result = 0
return result
print("\n\nRecursion Example Results")
tri_recursion(6)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
Recursion Example Results
1
3
6
10
15
21
Process finished with exit code 0
pass语句,空函数
函数定义不能为空,但是如果您出于某种原因写了无内容的函数定义,请使用 pass 语句来避免错误。
def myFunc():
pass
解包参数列表
**如果给位置形参传递的参数在一个列表中或者元组中时,可以对列表或者元组进行解包,再传递,解包的方式和任意个数的形参形式一样 " *arg " **
解包列表
在函数内部,将*arrg作为元组.
def myFunc(*arg):
print(type(arg), arg)
myFunc(*[1,2,3,4,5,6])
lst = ['a', 'b', 'c', 'd']
myFunc(*lst)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
<class 'tuple'> (1, 2, 3, 4, 5, 6)
<class 'tuple'> ('a', 'b', 'c', 'd')
Process finished with exit code 0
解包元组
def myFunc(*arg):
print(type(arg), arg)
myFunc(*(1,2,3,4,5,6))
t = ('a', 'b', 'c', 'd')
myFunc(*t)
myFunc(t)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
<class 'tuple'> (1, 2, 3, 4, 5, 6)
<class 'tuple'> ('a', 'b', 'c', 'd')
<class 'tuple'> (('a', 'b', 'c', 'd'),)
Process finished with exit code 0
解包字典参数
解包字典与函数定义中的关键字形参的形式一样 " **kwargs"
def myFunc(**kwargs):
print(type(kwargs))
for k in kwargs:
print('key = ', k, 'value = ', kwargs[k])
myFunc(**{'a':1,'b':2,'c':3,'d':4})
print('*' * 50)
d = {'a':11, 'b':22, 'c':33, 'd':44}
myFunc(**d)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
<class 'dict'>
key = a value = 1
key = b value = 2
key = c value = 3
key = d value = 4
**************************************************
<class 'dict'>
key = a value = 11
key = b value = 22
key = c value = 33
key = d value = 44
Process finished with exit code 0
函数的文档字符串
函数体的第一个语句可以是字符串文字,它是可选的。
这个字符串文字是函数的文档字符串
有些工具使用文档字符串自动生成在线或印刷文档,或者让用户以交互式的形式浏览代码;在你编写的代码中包含文档字符串是一种很好的做法,所以要养成习惯。
def myFunc(**kwargs):
''' 这是一个文档字符串,
这个字符串可以用来描述函数的功能,返回值,使用方法等信息
'''
print(type(kwargs))
for k in kwargs:
print('key = ', k, 'value = ', kwargs[k])
myFunc(**{'a':1,'b':2,'c':3,'d':4})
print('*' * 50)
d = {'a':11, 'b':22, 'c':33, 'd':44}
myFunc(**d)
函数符号表
当调用一个函数的时候会给这个被调用的函数引入一个函数局部变量的新符号表。
更确切地说,函数中所有的变量赋值都将存储在局部符号表中,如果在函数中对有对变量进行引用,会首先在局部符号表中进行查找,如果找不到,然后在外层函数的局部符号表查找,如果还找不到,就在全局的符号表中进行查找,如果再找不到,就在Python的内置符号表中查找,再找不到就出错。
全局变量和外层函数的变量不能在函数内部直接赋值, 可以在引用变量的函数内部使用关键字global引用达到引用的目的
函数内部的同名局部变量覆盖外部全局变量
a = 100
def myFunc(arg):
a = 10
print('1 in myFunc: a = ', a)
if arg == 0:
a = -1
print('in myFunc_if: a= ', a)
print('2 in myFunc: a = ', a)
myFunc(0)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
1 in myFunc: a = 10
in myFunc_if: a= -1
2 in myFunc: a = -1
Process finished with exit code 0
函数内部无变量的引用,引用函数外部定义的全局变量
a = 100
def myFunc(arg):
#a = 10
print('1 in myFunc: a = ', a)
if arg == 0:
#a = -1
print('in myFunc_if: a= ', a)
print('2 in myFunc: a = ', a)
myFunc(0)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
1 in myFunc: a = 100
in myFunc_if: a= 100
2 in myFunc: a = 100
Process finished with exit code 0
在函数内部通过关键字global声明引用全局变量
a = 100
def myFunc():
global a
a = 10
print(a)
print('befor: ', a)
myFunc()
print('after: ', a)
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
befor: 100
10
after: 10
Process finished with exit code 0
在函数内部通过关键字nonlocal声明引用外层函数的局部变量
如果不使用nonlocal关键字,如果函数内部有一个和外层函数同名的变量,是无法对外层的同名变量引用的
a = 100
def myFunc():
a = 10
print('1. myFunc: ', a)
def inFunc():
a = 1
print('inFunc: ', a)
inFunc()
print('2. myFunc: ', a)
myFunc()
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
1. myFunc: 10
inFunc: 1
2. myFunc: 10
Process finished with exit code 0
使用关键字nonlocal引用外层同名局部变量
a = 100
def myFunc():
a = 10
print('1. myFunc: ', a)
def inFunc():
nonlocal a
a = 1
print('inFunc: ', a)
inFunc()
print('2. myFunc: ', a)
myFunc()
输出:
E:\Python3\Exercise\venv\Scripts\python.exe E:/Python3/Exercise/venv/02.py
1. myFunc: 10
inFunc: 1
2. myFunc: 1
Process finished with exit code 0