函数的基本使用
Python 函数全套完整笔记(定义、调用、返回值、参数详解)
一、函数基础概念
1.1 函数是什么?
函数其实就是一种组织代码、封装功能的方式。
程序类比理解:
-
函数 → 具备某一独立功能的工具
-
定义函数 → 事先制作、准备好工具
-
调用函数 → 遇到对应场景,直接拿来使用工具
1.2 为什么要使用函数?
在没有函数封装功能之前,想要重复使用某一段功能代码,只能反复复制粘贴,会产生严重问题:
-
代码冗余:大量重复代码,程序结构混乱、可读性极差
-
维护性、扩展性差:功能需要修改时,所有重复代码都要逐一修改,极易出错
1.3 函数使用原则与分类
1.3.1 核心原则
先定义、后调用,必须遵守,顺序颠倒程序报错。
1.3.2 函数两大分类
-
内置函数:Python 官方提前定义好的函数,可直接调用(如 print、input、len 等)
-
自定义函数:开发者根据业务需求,自己定义的功能函数
二、函数的定义
2.1 函数定义语法(标准完整版)
# 完整定义格式
def 函数名(参数1,参数2,参数3,...):
"""
函数功能描述
:param 参数1: 参数1大致介绍
:param 参数2: 参数2大致介绍
:param 参数3: 参数3大致介绍
:return: 介绍一下函数的返回值
"""
代码1
代码2
代码3
return 值
2.1.1 示例:简易登录函数
def login():
username = input("请输入您的用户名:").strip()
password = input("请输入您的用户名:").strip()
if username == "egon" and password == "123":
print('登录成功')
else:
print('登录失败')
2.2 定义函数的底层逻辑与特性
定义函数与定义普通变量本质逻辑一致,都是绑定内存地址:
x = 10
print(x) # 打印普通变量名,输出变量值
print(login) # 打印函数名,输出函数的内存地址
核心特性:定义函数阶段,只检测语法,不执行函数体代码。
即使函数体内代码语法错误,只要定义阶段语法无误,不会报错,调用时才会触发报错。
# 定义时不报错,调用才会报错
def func():
if 1==1
print("ok")
2.3 函数定义的三种形式
2.3.1 无参函数
定义函数时,括号内无任何参数,适用于固定功能、无需传入数据的场景。
def say_hello():
print("="*50)
print('welcome to home page')
print("="*50)
say_hello()
2.3.2 有参函数
定义函数时,括号内指定形参,调用时必须传入对应实参,根据传入数据实现动态功能。
# 两数求和函数
def my_sum(x,y):
print(x + y)
my_sum(1,2)
# 带参数登录函数
def login(username, password):
if username == "egon" and password == "123":
print('登录成功')
else:
print('登录失败')
login("egon","aaa")
2.3.3 空函数
函数体使用 pass 占位,无实际代码逻辑,用于项目架构搭建、先定义功能占位,后续补充逻辑。
def register():
"""注册功能"""
pass
def login():
"""登录功能"""
pass
def withdraw():
"""取款功能"""
pass
三、函数的调用
3.1 调用语法
语法:函数名(),加括号即可触发函数内部代码执行
login()
login()
login()
报错提醒:只有函数可以加括号调用,普通变量、None 值均不能调用
# 错误写法
x = 10
x()
x = None
x()
3.2 调用函数的执行逻辑
调用函数时,程序会跳转执行函数体内部所有代码,执行完毕后回到调用位置继续执行后续代码。
3.2.1 嵌套调用练习1
def bar():
print('from bar')
def foo():
print('from foo')
bar()
foo()
3.2.2 嵌套调用练习2(先定义后调用,无顺序问题)
def foo():
print('from foo')
bar()
def bar():
print('from bar')
foo()
3.2.3 嵌套调用练习3(报错案例)
# 报错:调用foo时,bar还未定义
def foo():
print('from foo')
bar()
foo()
def bar():
print('from bar')
四、函数返回值 return
4.1 return 核心特性
-
return 是函数结束的唯一标志:函数内可写多个 return,只要执行任意一个,函数立即终止,后续代码不再执行
-
return 会将后面的值,作为本次函数调用的结果返回
def foo():
print("hello")
return 1
print("world")
return 2
print("egon")
return 3
foo()
4.1.1 示例:返回两数最大值
def foo(x, y):
if x > y:
return x
else:
return y
res = foo(3, 5)
print(res * 12)
4.2 return 返回值规则
-
函数无 return、或 return 后无值,默认返回 None
-
return 后跟单个值,直接返回该值本身(任意数据类型)
-
return 后跟多个值(逗号分隔),会自动封装为元组返回
def foo():
print('hello')
print('xx')
print('yyy')
return 111, "aaa", [333, 444]
res = foo()
print(res)
4.3 函数调用的三种格式
def foo(x, y):
if x > y:
return x
else:
return y
4.3.1 语句形式:仅执行功能,不接收返回值
foo(1, 2)
4.3.2 表达式形式:接收返回值并二次运算
res = foo(1,2) * 10
4.3.3 函数调用作为另一个函数的参数
res = foo(foo(5,9),11)
print(res)
五、函数参数核心详解(形参、实参)
5.1 参数基础定义
-
形参:定义函数时括号内的参数,本质是变量名
-
实参:调用函数时括号内传入的值,本质是变量值
-
绑定关系:调用函数时,实参值绑定形参;函数执行结束,绑定解除,资源回收
def foo(x,y):
# x = 1
# y = 2
pass
foo(1,2)
5.2 位置参数
5.2.1 位置形参
定义函数时,从左到右依次定义的形参,必须传值,缺一不可、多一不行。
def foo(x, y, z):
print(x, y, z)
# 正常传参
foo(111,222,333)
# 报错:参数过多
# foo(111,222,333,444)
# 报错:参数缺失
# foo(111,222)
5.2.2 位置实参
调用函数时,按从左到右的位置顺序传值,位置一一对应,顺序错误则赋值错误。
foo(111,222,333)
foo(333,111,222)
5.3 关键字参数(实参)
调用函数时,以 key=value 形式指名赋值,无需遵循位置顺序。
5.3.1 核心注意事项
-
位置实参与关键字实参可以混用,但位置实参必须在前,关键字实参在后
-
同一个形参不能重复赋值
def foo(x, y, z):
print(x, y, z)
# 正确混用
foo(111, 666, z=333, y=222)
# 纯关键字传参
foo(z=333,y=222,x=111)
# 正确写法
foo("egon", gender='male', age=18)
# 错误写法:位置参数在后
# register(name="egon",18,gender='male')
5.4 默认参数(形参)
定义函数时,提前为形参赋值,调用函数时可省略该参数,自动使用默认值。
5.4.1 三大注意点
-
默认形参必须放在位置形参后方
-
默认参数仅在函数定义阶段赋值一次,存储的是内存地址
-
默认参数建议使用不可变类型,避免可变类型带来的逻辑隐患
5.4.2 示例1:基础默认参数
def register(name, age, gender='male'):
print(name, age, gender)
register('egon', 18)
register('tom', 19)
register('jack', 38)
register('lili', 19, 'female')
5.4.3 示例2:默认参数定义阶段赋值特性
m = 10
def foo(x, y=m):
print(x, y)
foo(1)
5.4.4 示例3:可变类型默认参数隐患
m = [111,222,333]
def foo(x, y=m):
print(x, y)
foo(1)
m.append(666)
foo(1)
5.4.5 示例4:默认参数最优写法(规避可变类型隐患)
def register(name, hobby, hobbies=None):
if hobbies is None:
hobbies = []
hobbies.append(hobby)
print('%s 爱好是 %s' % (name, hobbies))
register('egon', 'basketball')
register('tom', 'read')
register('jack', 'music')
register('lili','sleep',['xxx','yyy'])
5.5 可变长参数 * 与 **
适用场景:调用函数时传入的实参个数不固定、溢出,用于接收多余实参。
溢出实参分为两种:溢出位置实参、溢出关键字实参,对应两种可变参数。
5.5.1 *args 接收溢出位置实参
将所有溢出的位置实参打包成元组,赋值给 args。
def foo(x,y,*z):
print(x,y,z)
foo(1,2,3,4,5)
# 累加器案例
def foo(*nums):
res = 0
for i in nums:
res += i
print(res)
foo(1, 2, 3, 4, 5)
foo(1, 2)
5.5.2 **kwargs 接收溢出关键字实参
将所有溢出的关键字实参打包成字典,赋值给 kwargs。
def foo(x, y, **z):
print(x, y)
print(z)
foo(1, 2, a=1, b=2, c=3)
5.5.3 * 在实参中的用法(打散序列)
* 可遍历序列(列表、字符串、元组、字典键),将序列打散为位置实参传入函数。
def foo(x, y, z):
print(x, y, z)
foo(1, *[222, 333]) # 等价 foo(1,222,333)
foo(1, *"he") # 等价 foo(1,"h","e")
foo(1, *"hello") # 等价 foo(1,"h","e","l","l","o")
foo(1, *{"k1":111,"k2":333}) # 仅打散键:foo(1,"k1","k2")
5.5.4 ** 在实参中的用法(打散字典)
** 仅可后跟字典,将字典打散为关键字实参传入函数。
def foo(x, y, z):
print(x, y, z)
foo(111, **{"z": 333, "y": 222}) # 等价 foo(111,y=222,z=333)
# 报错:多余关键字参数
# foo(111, **{"z": 333, "y": 222, "aaa": 333})
5.5.5 通用参数组合:*args、**kwargs
行业通用写法:*args 接收任意位置参数,**kwargs 接收任意关键字参数,适配所有传参场景。
def wrapper(*args, **kwargs):
print(args, kwargs)
index(*args, **kwargs)
5.6 命名关键字参数
定义在 *args 之后、**kwargs 之前的参数,必须以关键字形式传参,可设置默认值。
5.6.1 核心特点
-
无默认值的命名关键字参数,调用时必须手动传值
-
传值方式固定:只能用 key=value 关键字传参
def foo(x, y=111, *args, m=666, n, **kwargs):
print("x:", x)
print("y:", y)
print("args: ", args)
print("m: ", m)
print("n:", n)
print("kwargs: ", kwargs)
# 完整传参调用
foo(1,222,333,444,555,m=6666666,n=777,a=1,b=2,c=3)
# 报错:缺失必填命名关键字参数 n
# foo(1,222,333,444,555,a=1,b=2,c=3)

浙公网安备 33010602011771号