函数
【一】函数的定义
- 函数的定义就相当于事先将函数体代码保存起来,然后将内存地址赋值给函数名,函数名就是对这段代码的引用,这和变量的定义是相似的。
函数的语法
def 函数名(参数1,参数2,...):
函数体
return 值
-
def: 定义函数的关键字;
-
函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;
-
括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型;
-
冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;
-
函数体:由语句和表达式组成;
-
return 值:定义函数的返回值,return是可有可无的。
【1】无参无返回值
def sss():
user=input('user>>: ').strip()
pwd=input('password>>: ').strip()
【2】有参无返回值
- 参数是函数的调用者向函数体传值的媒介
def greet(name):
print(f"Hello, {name}!")
greet("Dream") # Output: Hello, Dream!
def add_numbers(a, b):
result = a + b
print(f"The sum of {a} and {b} is {result}")
add_numbers(3, 5) # Output: The sum of 3 and 5 is 8
【3】有参有返回值
# 定义一个函数,函数有两个参数
def add_numbers(a, b):
result = a + b
print(f"The sum of {a} and {b} is {result}")
# 使用 return 关键字将想要返回的结果返回出去
return result
res = add_numbers(3, 5) # Output: The sum of 3 and 5 is 8
print(res) # 8
def rectangle_info(length, width):
area = length * width
perimeter = 2 * (length + width)
return area, perimeter
# 解压赋值
area, perimeter = rectangle_info(4, 5)
print(f"Area: {area}, Perimeter: {perimeter}")
# Area: 20, Perimeter: 18
【二】函数三种调用方式
【1】直接调用
函数名() ---> 调用函数
def add(x, y):
return x + y
# 直接调用函数,拿到对应的结果
result = add(3, 5)
print(result) # 8
【2】表达式调用
def subtract(x, y):
return x - y
# 将定义好的函数地址给对应的变量
operation = subtract
# 通过给定的变量进行调用
result = operation(10, 5)
print(result) # 5
【3】函数作为参数
# 【3】触发这个函数 带入参数x 参数y
def multiply(x, y):
# 计算出返回值
return x * y
def operate(func, x, y):
# 【2】函数地址传过来 带参数过来
# 返回值是 函数地址(参数x,参数y)
# 【4】接收到返回值并返回
return func(x, y)
# 【1】operate 函数 有3个参数 : 函数地址 参数x 参数y
result = operate(multiply, 4, 6)
# 【5】拿到返回值
print(result)
【三】函数的参数
【1】形参和实参
- 函数的参数分为形式参数和实际参数,简称形参和实参
- 形参即在定义函数时,括号内声明的参数。
- 形参本质就是一个变量名,用来接收外部传来的值。
- 实参即在调用函数时,括号内传入的值
- 值可以是常量、变量、表达式或三者的组合:
- 形参即在定义函数时,括号内声明的参数。
def add(x, y):
return x + y
# 1:实参是常量
res_first = add(1, 2)
print(res_first) # 3
# 2:实参是变量
x = 5
y = 6
res_second = add(x, y)
print(res_second) # 11
# 3:实参是表达式
res_third = add(10 * 2, 10 * add(3, 4))
print(res_third) # 90
# 4:实参可以是常量、变量、表达式的任意组合
a = 2
res_forth = add(a, 10 * add(3, 4))
print(res_forth) # 72
【2】位置传参
- 位置即顺序,位置参数指的是按顺序定义的参数
有位置参数而不传值会报错*
# 定义位置形参:name,age,sex,三者都必须被传值
def register(name, age, sex):
print('Name:%s Age:%s Sex:%s' % (name, age, sex))
register() # TypeError:缺少3个位置参数
'''
Traceback (most recent call last):
File "E:\PythonProjects\01.py", line 175, in <module>
register() # TypeError:缺少3个位置参数
TypeError: register() missing 3 required positional arguments: 'name', 'age', and 'sex'
'''
不按位置传参会导致变量错误
# 定义位置形参:name,age,sex,三者都必须被传值
def register(name, age, sex):
print('Name:%s Age:%s Sex:%s' % (name, age, sex))
register(18, "男", "Dream")
# Name:18 Age:男 Sex:Dream
【3】关键字传参
在调用函数时,实参可以是key=value的形式,称为关键字参数
# 定义位置形参:name,age,sex,三者都必须被传值
def register(name, age, sex):
print('Name:%s Age:%s Sex:%s' % (name, age, sex))
# 根据指定关键字进行传参,不能多传参数,也不能少传参数
register(name="Dream", age=18, sex="男")
# Name:Dream Age:18 Sex:男
# 定义位置形参:name,age,sex,三者都必须被传值
def register(name, age, sex):
print('Name:%s Age:%s Sex:%s' % (name, age, sex))
# 根据指定关键字进行传参,可以不按顺序传参
register(sex="男", name="Dream", age=18)
# Name:Dream Age:18 Sex:男
【4】位置和关键字传参数
但必须保证关键字参数在位置参数后面,且不可以对一个形参重复赋值
# 定义位置形参:name,age,sex,三者都必须被传值
def register(name, age, sex):
print('Name:%s Age:%s Sex:%s' % (name, age, sex))
# 可以使用关键字和位置参数混合传参,但是一定要位置参数在前,关键字参数在后
register("Dream", age=18, sex="男")
# Name:Dream Age:18 Sex:男
【5】默认参数
在函数定义阶段的时候定义在函数名后面的 () 里面的参数可以给默认值位置参数给了默认值之后 在函数调用时,可以不指定默认参数的值,不给值默认就是默认值如果给了新值就会被新值覆盖掉
def student(name, gender='male'):
print(f' my name is {name} my gender is {gender}')
#给了name但是没给 gender , gender使用的就是默认的值 male
student('dream')
# 寄给name有给gender , 给了 新值则覆盖掉默认值
student('dream',gender='other')
'''
# num_list 可变数据类型 ---> 定义一次下一次修改列表会影响到原来列表
def app_list(num, num_list=[]):
num_list.append(num)
print(num_list)
app_list(1)
app_list(2)
app_list(3)
[1,2,3]
# num_list 每一次调用函数都是一个新的列表所以值只会是最后一个
def app_list(num):
num_list = []
num_list.append(num)
print(num_list)
app_list(1)
app_list(2)
app_list(3)
[3]
num_list = []
def app_list(num):
global num_list
num_list = []
num_list.append(num)
app_list(1)
app_list(2)
app_list(3)
print(num_list)
【6】可变长参数
参数的长度可变指的是在调用函数时,实参的个数可以不固定
- 而在调用函数时,实参的定义无非是按位置或者按关键字两种形式
[1]*args
任意类型参数
- 如果在最后一个形参名前加
*
号,那么在调用函数时,溢出的位置实参,都会被*
接收,以元组的形式保存下来赋值给该形参
# 在最后一个形参名args前加*号
def foo(x, y, z=1, *args):
print(x)
print(y)
print(z)
print(args)
foo(1, 2, 3, 4, 5, 6, 7)
# 实参1、2、3按位置为形参x、y、z赋值
# 多余的位置实参4、5、6、7都被*接收,以元组的形式保存下来,赋值给args
# 即args=(4, 5, 6,7)
- 如果形参为常规的参数(位置或默认),实参仍可以是
*
的形式
def foo(x, y, z=3):
print(x)
print(y)
print(z)
foo(*[1, 2]) # 等同于foo(1,2)
解包
def foo(x, y, *args):
print(x)
print(y)
print(args)
L = [3, 4, 5]
foo(1, 2, *L)
# *L就相当于位置参数3,4,5 ----> 解包
# 对应到函数中就是,foo(1,2,*L)就等同于foo(1,2,3,4,5)
如果在传入 L 时没有加 *
,那 L 就只是一个普通的位置参数了
def foo(x, y, *args):
print(x)
print(y)
print(args)
L = [3, 4, 5]
foo(1, 2, L)
# 如果在传入 L 时没有加 `*` ,那 L 就只是一个普通的位置参数了
# ([3, 4, 5],)
[2]*kwargs
- 如果在最后一个形参名前加
**
号,那么在调用函数时,溢出的关键字参数,都会被**
接收,以字典的形式保存下来赋值给该形参
def foo(x, **kwargs): # 在最后一个参数kwargs前加**
print(x)
print(kwargs)
foo(y=2, x=1, z=3)
# 溢出的关键字实参y=2,z=3都被**接收,以字典的形式保存下来,赋值给kwargs
# 1
# {'y': 2, 'z': 3}
- 如果我们事先生成了一个字典,仍然是可以传值给
**kwargs
的
ef foo(x, y, **kwargs):
print(x)
print(y)
print(kwargs)
dic = {'a': 1, 'b': 2}
foo(1, 2, **dic)
# **dic就相当于关键字参数a=1,b=2,foo(1,2,**dic)
# 等同foo(1,2,a=1,b=2)
# 1
# 2
# {'a': 1, 'b': 2}
- 如果形参为常规参数(位置或默认),实参仍可以是
**
的形式
ef foo(x, y, z=3):
print(x)
print(y)
print(z)
foo(**{'x': 1, 'y': 2}) # 等同于foo(y=2,x=1)
【7】命名关键字参数
需要在定义形参时,用 *
作为一个分隔符号,*
号之后的形参称为命名关键字参数
def register(name, age, *, sex, height): # sex,height为命名关键字参数
pass
# 正确使用
register('Dream', 18, sex='male', height='1.8m')
# TypeError:未使用关键字的形式为sex和height传值
register('Dream', 18, 'male', '1.8m')
# TypeError没有为命名关键字参数height传值。
register('Dream', 18, height='1.8m')
【8】混合使用
- 综上所述所有参数可任意组合使用,但定义顺序必须是:
- 位置参数、默认参数、*args 、命名关键字参数、***kwargs
- 可变参数args与关键字参数*kwargs通常是组合在一起使用的
- 如果一个函数的形参为
**args
与**kwargs
,那么代表该函数可以接收任何形式、任意长度的参数 - 所有位置参数、默认参数、*args 、**kwargs 混合使用的时候不允许使用关键字参数
- 所有位置参数、默认参数、*args 、**kwargs **** kwargs 必须在 *args 之后