定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。
在函数定义时函数名后面括号中的参数就是形式参数,简称“形参”。
def get_number_remainder(a, b):
generate_list = list(range(a, b + 1))
remainder_list = []
for i in generate_list:
if i % 5 != 0 and i % 3 != 0:
remainder_list.append(i)
return remainder_list
上述代码中的a,b都是形式参数
在调用函数时,函数名后面括号中的参数称为实际参数,也就是函数的调用者给函数的参数。简称“实参”
a = get_number_remainder(200, 300)
在python中。根据实际参数类型的不同。 函数传参可分为“值传参”和“引用传参即地址”
注意:函数参数进行值传递后,若形参的值发生改变,不会影响实参的值;而函数参数继续引用传递后,改变形参的值,实参的值也会一同改变。至于为什么会这样根底层的储存机制有关。 即基本类型储存值。引用类型储存地址。后面会解释传参机制。
a = 100
def get_number(mag):
mag = str(mag) + '-------这里改变了参数的值'
print(mag)
get_number(a)
print(a)
100-------这里改变了参数的值
----------------------------
100
很明显对于基本类型无论我们怎么操作形式参数其实际参数不会受到影响。
a = {
"name": "小王",
"age": 28
}
def get_obj(obj):
obj['name'] = "jack"
print(obj)
get_obj(a)
print(a)
{'name': 'jack', 'age': 28}
{'name': 'jack', 'age': 28}
对于引用类型来说。我们改变了形式参数的值后实际参数的值也会跟着改变。
这种传参方式要求。在调用函数时传入的实际参数的位置和数量必须对应一致。
示例一
def get_data(a):
print(a)
get_data(100, 200)
Traceback (most recent call last):
File "/Users/apple/Documents/重要文件/python3/python21.py", line 15, in
get_data(100, 200)
TypeError: get_data() takes 1 positional argument but 2 were given
示例二
def get_data(a, b):
print(a, b)
get_data(100)
Traceback (most recent call last):
File "/Users/apple/Documents/重要文件/python3/python21.py", line 15, in
get_data(100)
TypeError: get_data() missing 1 required positional argument: 'b'
示例三
def get_data(a, b):
print(a, b)
get_data(100, 200)
100 200
上述代码。示例一在函数调用时多传一个参数。 示例二在调用时少传了一个参数。此时都会抛出异常。 只有示例三当实际参数和形式参数的数量相等时代码正常执行并打印结果。
1 当实际参数和 形式参数的类型不一致时会抛出异常
def get_data(a, b):
print(100 + a)
print("python" + b)
get_data("3.7", 100)
Traceback (most recent call last):
File "/Users/apple/Documents/重要文件/python3/python21.py", line 16, in
get_data("3.7", 100)
File "/Users/apple/Documents/重要文件/python3/python21.py", line 13, in get_data
print(100 + a)
TypeError: unsupported operand type(s) for +: 'int' and 'str'
从上述函数中我们可以很明显的看出a应该是数字类型。 b应该是字符串类型。而我们在调用函数的时候虽然保证了参数数量的一直。但是讲参数的位置做了调换最后导致异常。
def get_data(a, b):
print(100 + a)
print("python" + b)
get_data(100, '3.7')
200
python3.7
此时当我们交换了参数的位置时同时也得到了正确的结果。 与此同时我们可以用前面的isinstance()检查我们的参数是否符合我们的类型。
1 产生的结果和预期不符
def get_data(a, b):
d = a + 100 * b
print(d)
get_data(120, 200)
get_data(200, 120)
# 正确结果
20120
------------------
# 错误结果
12200
调用函数时,如果指定的实际参数和形式参数的位置不一致,但它们的数据类型相同,那么程序将不会抛出异常,只不过导致运行结果和预期不符
关键字参数是指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。
def get_data(a, b):
d = a + 100 * b
print(d)
# 关键字传参
get_data(a=120, b=200)
# 对位传参
get_data(120, 200)
20120
20120
我们发现对于一个函数而言,在调用的时候既可以用对位传参, 也可以使用关键字传参。但是很明显关键字传参很好的解决了对位传参代码的弊端。
那么对位传参和关键字传参能不能搭配使用呢?答案是肯定的,看如下示例
1。示例一
def get_data(a, b):
d = a + 100 * b
print(d)
# 关键字传参
get_data(120, b=200)
20120
2 示例二
def get_data(a, b):
d = a + 100 * b
print(d)
# 关键字传参
get_data(a =120, 200)
File "/Users/apple/Documents/重要文件/python3/python21.py", line 17
get_data(a =120, 200)
^
SyntaxError: positional argument follows keyword argument
从上述示例可以看出对位传参和关键字传参是可以搭配使用的。 但是前提是对位传参必须在关键字参数之前,
在调用函数时如果不指定某个参数,Python 解释器会抛出异常。为了解决这个问题,Python 允许为参数设置默认值,即在定义函数时,直接给形式参数指定一个默认值。这样的话,即便调用函数时没有给拥有默认值的形参传递参数,该参数可以直接使用定义函数时设置的默认值。
def get_data(a, b = 200):
d = a + 100 * b
print(d)
# 关键字传参
get_data(a= 100 )
20100
上述代码函数需要接收两个参数。然而我们在调用的时候只传递了一个参数。代码正常运行而且得到了正确的结果,这是因为我们给b设置了默认的参数。在计算时发现b没有传值则或使用默认的200参与计算。如果给设置了默认参数的变量在函数调用时有传了值会发生什么情况呢?
def get_data(a, b=200):
d = a + 100 * b
print(d)
# 关键字传参
get_data(100, 300)
30100
我们发现此时我们虽然给b设置了默认参数。 但是在调用的时候同时也给b传了值。 这时b不在使用默认值了而是以实际参数的值为准。
def get_data(b=200, a):
d = a + 100 * b
print(d)
get_data(100)
File "/Users/apple/Documents/重要文件/python3/python21.py", line 12
def get_data(b=200, a):
^
SyntaxError: non-default argument follows default argument
--------------------------------
def get_data(b=200, a):
d = a + 100 * b
print(d)
get_data(a = 100)
File "/Users/apple/Documents/重要文件/python3/python21.py", line 12
def get_data(b=200, a):
^
SyntaxError: non-default argument follows default argument
通过上述代码应该注意的是 :一是必选参数在前,默认参数在后,否则Python的解释器会报错