一、函数定义
函数能提高应用的模块性,和代码的重复利用率。
1、语法
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
2、函数定义
>>> def hello() :
... print("Hello World!")
...
>>> hello()
Hello World!
3、过程定义
>>> hello()
Hello World!
>>> def hello():
... #定义函数
... print ("Hello World!")
... return 0
...
>>> a = hello()
Hello World!
>>> print(a)
0
>>> def test():
... #定义过程
... print("This is a girl")
...
>>> b = test()
This is a girl
>>> print(b)
None
函数和过程,函数比过程多了一个return的返回值。 函数和过程其实在python中没有过多的界限,当有return时,则输出返回值,当没有return,则返回None.
使用函数的好处:
- 代码重复利用
- 可扩展性
- 保持一致性
def bian():
print("便便么么哒")
def hello():
print ("Hello World!")
bian()
def test():
print("This is a girl")
bian()
a = hello()
b = test()
print(a)
print(b)
#输出
Hello World!
便便么么哒
This is a girl
便便么么哒
None
None
二、函数参数及调用
1、返回值
return两个作用:
- 需要用一个变量来接受程序结束后返回的结果
- 它是作为一个结束符,终止程序运行
def test():
print("in the test")
return 0
print(test)
x = test()
print(x)#没有输出
输出:
in the test
0
return 0后面的代码就不执行了,只执行return前面的代码;变量x接受了test()函数结束后的返回结果 。
return返回值分三种情况:
- 返回None,没有定义时返回
- 返回一个值
- 返回多个值,1个元组(tuple)
def test():
print("in the test")
#返回None
def test_1():
print("in the test_1")
return 0
#返回0
def test_2():
print("in the test_2")
return 1,"Good",[2,3];{"bianbian":"18岁"}
#返回多个值
x = test()
y = test_1()
z = test_2()
print(x,y,z)
结果:
in the test
in the test_1
in the test_2
None 0 (1, 'Good', [2, 3], {'bianbian': '18岁'})
2、有参数函数调用
形参:指的是形式参数,是虚拟的,不占用内存空间,形参单元只有被调用的时才分配内存单元
实参:指的是实际参数,是一个变量,占用内存空间,数据传递单向,实参传给形参,形参不能传给实参
def test(x,y):
#x,y是行参
print(x)
print(y)
test(1,2)
#1,2是实参
输出
1
2
3、位置参数
实际参数和形式参数是一一对应的,如果调换位置,x和y被调用的时,位置也会互换
def test(x,y):
print(x)
print(y)
print("-------互换参数前------")
test(1,2)
print("-------互换参数后------")
test(2,1)
多一个或者少一个参数,都是不行的
def test(x,y):
print(x)
print(y)
print("-------多一个参数------")
test(2,1,8)
print("-------少一个参数------")
test(2)
Traceback (most recent call last):
File "/Users/bianbian/PycharmProjects/test/test 4.py", line 5, in <module>
test(2,1,8)
TypeError: test() takes 2 positional arguments but 3 were given
4、关键字参数
关键字传参不需要一一对应,只需要你指定你的哪个形参调用哪一个实参即可
def test(x,y):
print(x)
print(y)
print("-------互换参数前------")
test(x=1,y=2)
print("-------互换参数后------")
test(y=2,x=1)
结果:
-------互换参数前------
1
2
-------互换参数后------
1
2
①位置参数在前,关键字参数在后
def test(x,y):
print(x)
print(y)
test(1,y=2)
结果:
1
2
下面这样写会报错,报错的原因是:实参1已传给形参x,x=2又传了一次,所以报错。
def test(x,y):
print(x)
print(y)
test(1,x=2)
Traceback (most recent call last):
File "/Users/bianbian/PycharmProjects/test/test 4.py", line 4, in <module>
test(1,x=2)
TypeError: test() got multiple values for argument 'x'
②关键字在前,位置参数在后
下面四个例子,前两个运行报错,后两个可以正常运行,我们可以得出一个结论:关键字参数是不能写在位置参数前面的。
def test(x,y):
print(x)
print(y)
test(y=2,1)
test(y=2,1)
^
SyntaxError: positional argument follows keyword argument
def test(x,y):
print(x)
print(y)
test(1,y=2,3)
test(1,y=2,3)
^
SyntaxError: positional argument follows keyword argument
def test(x,y,z):
print(x)
print(y)
print(z)
test(1,2,z=3)
结果: 1 2 3
def test(x,y,z):
print(x)
print(y)
print(z)
test(1,y=2,z=3)
结果:
1
2
3
总结:
- 既有关键字,又有位置参数时,是按位置参数的顺序传参
- 关键字参数不能写在位置参数前面
三、非固定参数
1、默认参数
默认参数指,在传参之前,先给参数制定一个默认的值。当我们调用函数时,默认参数是非必须传递的。
def test(x,y=2):
print(x)
print(y)
print("-------1--------")
test(1)#没有给默认参数传值
print("-------2--------")
test(1,y=3)#给默认参数传关键字参数
print("-------3--------")
test(1,3)#给默认参数传位置参数
结果:
-------1--------
1
2
-------2--------
1
3
-------3--------
1
3
默认参数用途:
- 安装默认软件(def test(x,soft=True))
- 传递一下默认的值(定义mysql的默认端口号:def count(host,port=3306))????
2、参数组
我们可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述参数不同,声明时不会命名。基本语法如下:
def functionname([formal_args,] *var_args_tuple ):
"函数_文档字符串"
function_suite
return [expression]
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
- 非固定位置参数传参(*args)
- 非固定关键字传参(**kwargs)
2.1 非固定位置参数传参(*args)
(*args)接收N个位置参数,转换成元组的形式
(1)语法如下:
def test(*args):
#形参以*开头,args参数名可自行定义,建议按照规范定义成args
print(args)
test(1,2,3,4,5,6,7,8,8)
#输入多个位置参数
结果:
(1, 2, 3, 4, 5, 6, 7, 8, 8)
(2)传入列表:
def test(*args):
print(args)
print("-------什么都不传------")
test()
print("-------在传入的列表的前面加*,输出的args的元组形式------")
test(*[1,2,3,4,5])
print("-------在传入的列表的前面不加*,列表被当做单个位置参数,输出的结果是元组中的一个元素------")
test([1,2,3,4,5])
结果:
-------什么都不传------
()
-------在传入的列表的前面加*,输出的args的元组形式------
(1, 2, 3, 4, 5)
-------在传入的列表的前面不加*,列表被当做单个位置参数,输出的结果是元组中的一个元素------
([1, 2, 3, 4, 5],)
(3)位置参数和非固定位置参数
def test(x,*args):
print(x)
print(args)
test(1,2,3,4,5,6)
结果:
1
(2, 3, 4, 5, 6)
第1个参数,被当做位置参数,剩下的被当做非固定位置参数。
(4)关键字和非固定位置参数
def test(x,*args):
print(x)
print(args)
test(x=1,2,3,4,5,6)
结果:
test(x=1,2,3,4,5,6)
^
SyntaxError: positional argument follows keyword argument
因为x=1是关键字参数,*args是位置参数,而关键字参数不能再位置参数前面的,所以报错。
2.2 非固定关键字传参(**kwargs)
(**kwargs)把N个关键字参数,转换成字典形式。
(1)语法:
def test(**kwargs):
# #形参以**开头,kwargs参数名可自己定义,建议按照规范定义成kwargs
print(kwargs)
test(name="bianbian",sex="girl",age=18)
#传入多个关键字参数
结果:
{'name': 'bianbian', 'sex': 'girl', 'age': 18}
多个关键字参数转换成字典
(2)传入字典
def test(**kwargs):
print(kwargs)
test(**{'name': 'bianbian', 'sex': 'girl', 'age': 18})
结果:
{'name': 'bianbian', 'sex': 'girl', 'age': 18}
传入字典时,一定要在字典前面加**,否则就会报错
def test(**kwargs):
print(kwargs)
test({'name': 'bianbian', 'sex': 'girl', 'age': 18})
结果:
Traceback (most recent call last):
test({'name': 'bianbian', 'sex': 'girl', 'age': 18})
TypeError: test() takes 0 positional arguments but 1 was given
因为传入的字典被当做位置参数,所以被报类型错误,非固定关键字传字典,一定要加**
(3)配合位置参数使用
def test(name, **kwargs):
print(name)
print(kwargs)
print("------1个位置参数-----")
test("便便")
print("------1个位置参数,两个关键字参数------")
test("便便", age=18, sex="girl")
print("------3个关键字参数------")
test(name="bianbian", age=18, sex="girl")
结果:
------1个位置参数-----
便便 #输出1个位置参数
{} #没有输入关键字参数,所以输出空字典
------1个位置参数,两个关键字参数------
便便 #第1个位置参数
{'age': 18, 'sex': 'girl'}
#剩下关键字参数,转换成1个字典
------3个关键字参数------
bianbian
#第1个关键字参数
{'age': 18, 'sex': 'girl'}
#剩下的关键字参数,转换成1个字典
(4)位置参数、关键字和非固定关键字参数
如果遇到一个关键字传参和非固定关键字传参,
关键字参数
前后放的位置是不影响传参的,但是我们一般还是按顺序来。
def test(name,age=18,**kwargs):
print(name)
print(age)
print(kwargs)
print("------1-----")
test("便便", age=18, sex="girl")
print("------2-----")
test("便便", 18, sex="girl",love="peng")
print("------3------")
test("便便",sex="girl",love="peng",age=18)
结果:
------1-----
便便
18 #不传,显示默认参数
{'sex': 'girl'}
------2-----
便便
18 #传位置参数
{'sex': 'girl', 'love': 'peng'}
------3------
便便
18 #关键字参数,放在前后并没有影响
{'sex': 'girl', 'love': 'peng'}
(5)位置参数、关键字参数、非固定位置参数和非固定关键字参数
def test(name,age=18,*args,**kwargs):
print(name)
print(age)
print(args)
print(kwargs)
print("------第一种传参-----")
test("便便",18,1,2,3,4, sex="girl",love="peng")
print("------第二种传参-----")
test("便便",18,*[1,2,3,4],**{'sex':"girl",'love':"peng"})
结果:
------第一种传参-----
便便 #传name位置参数
18 #给age传位置参数
(1, 2, 3, 4)
#非固定位置参数,以转换成元组
{'sex': 'girl', 'love': 'peng'} # 非固定关键字参数,转换成字典
------第二种传参-----
便便
18
(1, 2, 3, 4) #以列表的形式传入,在列表前加*
{'sex': 'girl', 'love': 'peng'} #以字典的形式传入,在字典前加**
下面两种传参方法是不可以的
def test(name,age=18,*args,**kwargs):
print(name)
print(age)
print(args)
print(kwargs)
test("便便",age=18,1,2,3,4,sex="girl",love="peng")
结果:
test("便便",age=18,1,2,3,4,sex="girl",love="peng")
^
SyntaxError: positional argument follows keyword argument
因为age=18是关键字参数,而后面的*args是非固定位置参数,所以不管*args传入几个参数,它的本质都是位置参数,上面我们提到关键字参数是不能再位置参数的前面,所以报错了。
def test(name,age=18,*args,**kwargs):
print(name)
print(age)
print(args)
print(kwargs)
#test1("便便",age=18,1,2,3,4,sex="girl",love="peng")
test2("便便",18,sex="girl",love="peng",1,2,3,4)
结果:
test2("便便",18,sex="girl",love="peng",1,2,3,4)
^
SyntaxError: positional argument follows keyword argument
这样也是不可以的。
非固定关键字参数,本质也是关键字参数,是不能放在非固定位置参数的前面的。
四、总结
- 参数分为位置参数、关键字参数、默认参数、非固定位置参数和非固定关键字参数
- 位置参数之前传参,位置是不能调换的,多一个或者少一个参数都是不可以的。
- 关键字参数是不能放在位置参数前面的。
- 函数传参的位置一次是,位置参数,默认参数、非固定位置参数、非固定关键字参数(def test(name,age=18,*args,**kwargs))
- 关键字传参,可以不用考虑位置的前后问题