定义函数详解
定义函数使用关键字 def,后跟函数名与括号内的形参列表。函数语句从下一行开始,并且必须缩进。
函数可定义接收多种类型的值
Python 自定义函数可以接收多种类型的值,常见的包括:
1.数值类型:如整数(int)、浮点数(float)等。
2.字符串类型(str)。
3.列表(list)、**元组(tuple)和集合(set)**等序列类型。
4.字典(dict)。
5.布尔类型(bool)。
6.类对象和实例。
7.函数(可以将函数作为参数传递)。
8.None。(空)
基本上,Python 中的任何数据类型都可以作为函数的输入。
函数可定义不同类型的参数
在定义函数时 def name(): 语句 括号内一般会定义一些形参,用于其他方法的调用;以下是几种参数定义的方式:
位置参数
位置参数是最常见的参数类型,它们按照定义的顺序进行传递。调用函数时,需要按照定义的顺序传入对应的参数值。
在 Python 中,位置参数是指在函数调用时,按照参数在函数定义中的位置顺序来传递的值。
当定义一个函数时,参数在函数定义中的顺序决定了它们在调用时的位置。在调用函数时,必须按照相同的顺序提供相应的实际参数值。
##位置参数
def add(x, y):
return x + y
result = add(3, 5) # 调用add函数,并传入参数3和5
print(result) # 输出8
在使用 Python 位置参数时,有以下一些需要注意的点:
- 参数顺序必须正确:调用时参数的提供顺序要与函数定义时的顺序严格一致,否则可能导致结果不正确。
- 数量要匹配:提供的参数数量应与函数定义中要求的位置参数数量相同,过多或过少都会引发错误。
- 可读性:当函数参数较多时,仅依靠位置可能会使代码的理解和维护变得困难,需要清晰地理解每个位置参数的含义。
- 修改函数定义的影响:如果后续修改函数定义中位置参数的顺序或数量,可能会导致大量依赖该函数的代码需要修改。
- 与默认参数结合时:要注意默认参数在后面,位置参数在前面,且调用时不能跳过前面的位置参数去给后面的默认参数赋值。
默认参数
默认参数在函数定义时就给定了默认值,如果调用函数时没有传入对应的参数值,则会使用默认值。
##默认值参数
def power(x, n=2):
return x ** n
result1 = power(3) # 调用power函数,只传入一个参数,默认使用n=2
result2 = power(3, 4) # 调用power函数,传入两个参数,覆盖默认值
print(result1) # 输出9 3*3
print(result2) # 输出81 3*3*3*3
可变参数
可变参数允许传入任意数量的参数。在函数定义时,可以使用*args来表示可变参数。可变参数又分为可变位置参数、可变关键字参数;
可变位置参数
使用 *args 来接收任意数量的位置参数,这些参数会被收集到一个元组中。
##可变参数
def multiply(*args):
result = 1
for num in args:
result *= num
return result
result1 = multiply(2, 3, 4) # 调用multiply函数,传入3个参数
result2 = multiply(5, 6, 7, 8) # 调用multiply函数,传入4个参数
print(result1) # 输出24 1*2 2*3 6*4
print(result2) # 输出1680 1*5 5*6 30*7 210*8
可变关键字参数
使用 **kwargs 来接收任意数量的关键字参数,这些参数会被收集到一个字典中。
##关键字参数
def person_info(name, age, **kwargs):
print("姓名:", name)
print("年龄:", age)
for key, value in kwargs.items():
print(key + ":", value)
person_info("张三", 25, city="北京", gender="男")
# 输出:
# 姓名: 张三
# 年龄: 25
# city: 北京
# gender: 男
关键字参数
什么是关键字参数:关键字参数允许以键=值的形式传递参数,可以不按照定义的顺序传递。在函数定义时,可以使用**kwargs来表示可变关键字参数。 关键字参数传递要和key对应起来;
def my_function(name, age):
print(f"Name: {name}, Age: {age}")
my_function(age=25, name="Alice")
在这个例子中,age=25 和 name=“Alice” 就是关键字参数。与位置参数不同,关键字参数不是按照位置来对应函数定义中的参数,而是通过参数名来明确关联。这使得函数调用更加灵活和清晰,尤其是在参数较多的情况下,可以避免因参数位置错误而导致的问题。
特殊参数:
1.可变位置参数(*args):如前面所提到的,可以接收任意数量的位置参数,这些参数被收集到一个元组中。
2.*可变关键字参数(kwargs):可以接收任意数量的关键字参数,这些参数被收集到一个字典中。
这些都算特殊参数为函数提供了更大的灵活性和适应性,能够处理不同数量和组合的输入情况。
特殊参数结合 / 和 使用:
/ 和 * 是可选的。这些符号表明形参如何把参数值传递给函数:位置或关键字。关键字形参也叫作命名形参。
仅限位置形参应放在 / (正斜杠)前。/ 用于在逻辑上分割仅限位置形参与其它形参。
形参标记为仅限关键字,表明必须以关键字参数形式传递该形参,应在参数列表中第一个 仅限关键字 形参前添加 *。
##特殊参数
def a(arg):
print(arg)
def b(arg,/): #/前必须是位置参数使用
print(arg)
def c(*,arg): #*后必须是关键字参数使用 位置参数会报错
print(arg)
def d(arg1,/,arg2,*,arg3,arg4 = 5):
print(arg1,arg2,arg3,arg4)
##函数a无任何调用限制
a("今年10岁") #位置参数传递
a(arg = "今年11岁") #关键字参数传递
##函数b /前必须是位置参数使用 关键字参数会报错
b("鲜花和牛粪")
#b(arg = "心花怒放")
##函数c *后必须是关键字参数使用 位置参数会报错
#c("位置参数报错")
c(arg="关键字参数")
##函数d 组合使用
d("我是arg1","我是arg2我在/后*前管不着我",arg3 = "我是arg3",arg4=6)
#d(arg1 ="我是arg1",arg2="我是arg2我没有",arg3 = "我是arg3",arg4=6)
d("我是arg1",arg2="我是arg2我没有",arg3 = "我是arg3")
注意项:
使用 可变参数需要注意以下几点:
1、参数顺序:如果同时有普通位置参数和可变位置参数,普通位置参数要放在前面,可变位置参数放在后面。
def my_func(a, *args):
print(f"普通位置参数 a: {a}")
print(f"可变位置参数 args: {args}")
my_func([10,11], 20, 30)
2、命名冲突:要确保可变位置参数的名称(通常是 args)不会与函数内其他变量名称冲突。
3、参数处理:在函数内部处理 args 元组时,要注意可能存在不同类型的元素,需要根据实际情况进行合适的操作。
4、可迭代性:传递给可变位置参数的内容必须是可迭代的,否则可能会引发错误。
5、修改影响:修改 args 元组可能不会直接影响到外部传递的参数,因为它是一个副本。
def modify_args(*args):
args = (4, 5, 6) # 修改 args 元组
print(args)
modify_args(1, 2, 3)
6、在函数内部,可变关键字参数会被自动组装成一个字典。
7、调用函数时,使用任意数量的实参是最少见的选项。这些实参包含在元组中。在可变数量的实参之前,可能有若干个普通参数:
def write_multiple_items(file,separator,*args): # 任意普通参数
file.write(separator.json(args))
8、*args 形参后的任何形式参数只能是仅限关键字参数,即只能用作关键字参数,不能用作位置参数:
def concat(*args,sep="/"):
return sep.join(args)
#join 字符串方法接收一个可迭代对象作为参数,并使用指定的分隔符将其中字符串连接起来
concat("earth","mars","venus")
#concat("earth","mars","venus",sep=".")
9、解包实参列表指的是在将一个可迭代对象(如列表、元组等)在传递给函数时,将其元素分别展开作为独立的参数传递。
def my_func(a, b, c):
print(a, b, c)
data = [1, 2, 3]
my_func(*data) # 这里的 * 就是对列表 data 进行解包
总结:
1.使用仅限位置形参,可以让用户无法使用形参名。形参名没有实际意义时,强制调用函数的实参顺序时,或同时接收位置形参和关键字时,这种方式很有用。
2.当形参名有实际意义,且显式名称可以让函数定义更易理解时,阻止用户依赖传递实参的位置时,才使用关键字。
3.对于 API,使用仅限位置形参,可以防止未来修改形参名时造成破坏性的 API 变动。
函数注解
函数注解 是可选的用户自定义函数类型的元数据完整信息
标注 以字典的形式存放在函数的 annotations 属性中,并且不会影响函数的任何其他部分。
形参标注的定义方式是在形参名后加冒号,后面跟一个表达式,该表达式会被求值为标注的值。
返回值标注的定义方式是加组合符号 -> 该标注位于形参列表和表示 def 语句结束的冒号之间
def f(name : str = "传入string类型的名称",age: str = 'NBSP') ->str:
print("函数说明" , f.__annotations__)
print("函数参数说明",name,age)
return name + 'and' + age
f('sb')