Python基础③-函数篇
1.序言
本篇文章从基础的函数参数分类、实参传递方式和函数返回值的特性,到进制转换等实用技巧,再到函数的高级特性如嵌套定义、作为返回值和参数传递等等方面展开。此外,还会介绍all
与any
函数的使用,以及作用域、闭包和装饰器等重要概念。
无论你是 Python 编程的初学者,还是希望进一步提升编程技能的开发者,相信通过本文的学习,你将对 Python 函数有更深入的理解和掌握。
2.函数参数
2.1 参数分类及概念
- 形参(形式参数):在函数定义时,用于接收外部传入信息的变量,是函数定义时准备的“占位符”。例如:
def func(a, b): # a、b 就是形参,定义时用来接收后续调用传入的值print(a + b)
- 实参(实际参数):在调用函数时,实际传递给函数的信息,是实实在在的值或变量。比如:
func(3, 5) # 3、5 是实参,调用时传递给形参 a、b
2.2 实参传递方式
- 位置参数:按照形参定义的位置顺序传递参数。
def func(a, b):print(f"a: {a}, b: {b}")
func(10, 20) # 10 传给 a,20 传给 b,按位置对应
- 关键字参数:通过参数名来传递参数,无需严格遵循位置顺序
但位置参数要放在关键字参数前面,否则会报错,注意这里是有顺序之分的。
def func(a, b):print(f"a: {a}, b: {b}")
func(b=20, a=10) # 通过指定参数名,10 传给 a,20 传给 b
# 错误示例(位置参数放关键字参数后面)
# func(b=20, 10) # 这样会报错,位置参数不能在关键字参数之后
- 混合参数:位置参数和关键字参数一起使用,位置参数要放在前面。
def func(a, b, c):print(f"a: {a}, b: {b}, c: {c}")
func(1, c=3, b=2) # 1 是位置参数传给 a,b=2、c=3 是关键字参数,符合位置参数在前规则
2.3 动态参数
*args
:用于接收任意数量的位置参数,会将传入的位置参数打包成一个元组。
def func(*args):print(args)
func(1, 2, 3, 4) # 输出:(1, 2, 3, 4),接收到的多个位置参数被打包成元组
相当于说不限制你定义的这个函数要接收多少参数了。
**kwargs
:用于接收任意数量的关键字参数,会将传入的关键字参数打包成一个字典。
def func(**kwargs):print(kwargs)
func(name="张三", age=20) # 输出:{'name': '张三', 'age': 20},关键字参数被打包成字典
但这里在调用函数时必须要有指定,不可以直接写数值。
- 参数顺序:在函数定义中,参数顺序需遵循:位置参数 ->
*args
-> 默认参数 ->**kwargs
,否则会报错。示例:
def func(a, b, *args, c="哈哈", **kwargs):print(a, b, args, c, kwargs)
func(1, 2, 3, 4, c="呵呵", hello=456, haha_lou=654)
# 输出:1 2 (3, 4) 呵呵 {'hello': 456, 'haha_lou': 654}
# 解释:a=1(位置参数), b=2(位置参数), args=(3,4)(动态接收多余位置参数),
# c="呵呵"(传入值覆盖默认值), kwargs 接收剩余关键字参数
这里需要注意,如果你想要直接更改c的值,最简单省事的方法实际上就是直接令c=**
这种形式,
如果你按照顺序,比如说
def func(a, b, c="哈哈", *args **kwargs):
func(1, 2, 3, 4)
那你的c的数值运行后就变成3了。
3.函数返回值(return
)
3.1 基本概念
函数执行完毕后,会给调用方一个结果,这个结果就是返回值,由 return
语句控制。
3.2return
特性
- 函数中只要执行到
return
,函数会立即停止执行,return
后续的代码不再执行。
def func():print("执行到 return 前")returnprint("执行到 return 后,不会执行")
func()
# 输出:执行到 return 前
- 函数内没有
return
时,外界调用函数收到的返回值是None
。
def func():print("函数内无 return")
result = func()
print(result) # 输出:函数内无 return None
-
return
不同用法:只写
return
,后面不跟数据,外界收到None
(一般用于提前结束函数)。
def func():return
result = func()
print(result) # 输出:None
return
后跟一个值,外界能收到这个数据。
def func():return 10
result = func()
print(result) # 输出:10
return
后跟多个值,外界收到的是元组,包含所有返回值。
def func():return 1, 2, 3
result = func()
print(result) # 输出:(1, 2, 3)
在掌握了函数参数和返回值这些函数基础内容之后,我们换个角度,来了解一些 Python 中与数据表示相关的实用知识——进制转换。
它虽然和函数没有直接关联,但同样是 Python 编程基础篇里面需要认识到的知识点。
4.进制转换相关
4.1 十进制转其他进制
- 转二进制:使用
bin()
函数,将十进制数转成二进制字符串表示。
a = 18 # 十进制数
print(bin(a)) # 输出:0b10010 ,0b 是二进制标识
- 转八进制:使用
oct()
函数,将十进制数转成八进制字符串表示。
a = 18
print(oct(a)) # 输出:0o22 ,0o 是八进制标识
- 转十六进制:使用
hex()
函数,将十进制数转成十六进制字符串表示。
a = 18
print(hex(a)) # 输出:0x12 ,0x 是十六进制标识
4.2 其他进制转十进制
对于二进制、八进制、十六进制数转十进制,使用 int()
函数,指定 base
参数(二进制 base=2
,八进制 base=8
,十六进制 base=16
)。
# 二进制转十进制
a = 0b10010
print(int(a)) # 输出:18 ,将二进制数转成十进制
# 八进制转十进制
b = 0o22
print(int(b)) # 输出:18 ,将八进制数转成十进制
# 十六进制转十进制
c = 0x12
print(int(c)) # 输出:18 ,将十六进制数转成十进制
了解完进制转换这种数据处理技巧后,让我们再次聚焦到函数上,
深入探索Python函数的高级特性,这些特性会让你的函数编程更加灵活和强大。
5. 函数高级特性
5.1 函数嵌套定义
函数内部可以再定义函数,内层函数可访问外层函数的变量,外层函数可返回内层函数供外部使用,用于封装逻辑、实现闭包等场景。
def outer():message = "外层函数变量"def inner():# 访问外层函数的变量print(message) return inner # 返回内层函数# 调用外层函数,得到内层函数
inner_func = outer()
inner_func() # 输出:外层函数变量
5.2 函数作为返回值
函数执行后可返回另一个函数,让返回的函数后续按需调用,常用于根据条件动态生成函数逻辑。
def maker(flag):def add(a, b):return a + bdef sub(a, b):return a - b# 根据 flag 返回不同函数return add if flag else sub # 获取加法函数
add_func = maker(True)
result = add_func(3, 5)
print(result) # 输出:8# 获取减法函数
sub_func = maker(False)
result = sub_func(8, 3)
print(result) # 输出:5
5.3 函数作为参数传递
函数可以当作参数传给另一个函数,让被调用函数灵活执行不同逻辑,是回调函数、高阶函数的基础。
def target():print("我是目标函数")def caller(func):# 执行传入的函数func() caller(target) # 输出:我是目标函数
你看这里,target作为caller函数的输入,然而定义的caller函数会将传进去的参数当函数去执行,
那种样子就相当于执行target函数,就打印我是目标函数
出来了。
5.4 函数名的本质
函数名本质是变量,存储函数对象在内存中的地址,可赋值、传递,也能查看其指向的内存地址。
def func():print("函数执行")# 查看函数名对应的内存地址
print(func)
# 输出类似:<function func at 0x0000023...> # 赋值给新变量,新变量也指向该函数
new_func = func
new_func() # 输出:函数执行
5.5 多层函数嵌套执行流程
多层嵌套函数按“从外到内定义,从内到外执行”的顺序,理清调用层级和变量作用域是关键。
def func1():print(123)def func2():print(456)def func3():print(789)print(1)func3()print(2)func2()print(3)func1()
# 执行顺序与输出:
# 123(func1 外层执行)
# 456(func2 中层执行)
# 789(func3 内层执行)
# 1(func3 内层执行)
# 2(func3 执行完,回到 func2 中层执行)
# 3(func2 执行完,回到 func1 外层执行)
6. all
与any
函数
6.1 all
函数
主要用于接收可迭代对象(列表、元组等),判断所有元素是否都为真(非 0
、非空、非 None
等),全为真返回 True
,否则返回 False
。
# 列表元素全为真
list1 = [True, 1, "hello"]
print(all(list1)) # 输出:True # 列表含假值(0 视为假)
list2 = [1, 0, "world"]
print(all(list2)) # 输出:False # 空可迭代对象,返回 True(无元素可视为“所有元素都满足”)
list3 = []
print(all(list3)) # 输出:True
你可以把这个函数当成一个and
来看待。
6.2 any
函数
主要作用是接收可迭代对象,判断是否至少有一个元素为真,有一个及以上为真返回 True
,全为假返回 False
。
# 列表至少一个真(True 为真)
list1 = [False, 0, True]
print(any(list1)) # 输出:True # 列表全为假(0、空字符串、False 都为假)
list2 = [0, "", False]
print(any(list2)) # 输出:False # 空可迭代对象,返回 False(无元素可视为“没有元素满足”)
list3 = []
print(any(list3)) # 输出:False
6.3 对比与适用场景
函数 | 判定逻辑 | 典型场景 |
---|---|---|
all | 所有元素为真才返回 True | 校验一组条件是否全部满足 |
any | 至少一个元素为真返回 True | 校验一组条件是否有任意满足 |
我们已经学习了用于判断可迭代对象元素真假性的 all
和 any
函数,
接下来要探讨的是 Python 中变量作用域以及相关关键字,这对于理解函数内外变量的使用和修改规则还是很重要的。
7.作用域与关键字
7.1 作用域基础
Python 中变量有局部作用域(函数内)和全局作用域(函数外)。默认情况下,
函数内定义的变量是局部变量,只能在函数内使用。
函数外定义的变量是全局变量,可在整个脚本中使用。
7.2 global
:引入全局变量
作用则是在局部作用域(函数内) 中,明确声明使用全局变量,修改后会影响全局作用域的变量值。
# 全局变量
a = 10 def func():# 声明使用全局变量 aglobal a # 修改全局变量a = 20 print(f"函数内 a 的值: {a}")func()
# 全局变量已被修改
print(f"函数外 a 的值: {a}")
输出:
7.3 nonlocal
:引入外层局部变量
作用是在嵌套函数中,从外层(非全局)的局部作用域引入变量,修改后会影响外层局部作用域的变量值。
def func():# 外层函数的局部变量a = 10 def func2():# 引入外层函数的局部变量 anonlocal a # 修改外层函数的局部变量a = 20 print(f"内层函数 func2 中 a 的值: {a}")func2()# 外层函数的变量已被修改print(f"外层函数 func 中 a 的值: {a}") func()
输出:
掌握了变量作用域和 global
、nonlocal
关键字后,我们可以基于这些知识来理解 Python 中一个非常有用的概念——闭包。
8.闭包
就是嵌套函数中,内层函数引用了外层函数的变量(非全局),并且外层函数返回内层函数,这样的结构称为闭包。
主要用处在于让变量常驻内存
,即使外层函数执行完毕,内层函数仍可访问外层函数的变量,还可以有效防止不经意间全局变量的数值被更改。
def func():# 外层函数的变量a = 10 def inner():# 引入外层变量(非全局)nonlocal a a += 1 return a# 返回内层函数,形成闭包return inner # 获取闭包函数
closure = func()
# 每次调用闭包,操作的是外层函数的变量 a
print(closure()) # 输出: 11
print(closure()) # 输出: 12
说到底,闭包就是为我们提供了一种让变量常驻内存、保存状态的方法,
基于闭包的思想,我们可以进一步了解 Python 中的装饰器。
装饰器本质上是一种特殊的闭包,它能在不修改原函数代码的情况下为函数添加额外功能。
9.装饰器
9.1 定义
本质是一个闭包,用于在不修改原函数代码的前提下,为函数添加额外功能。
目前主要的用途有以下两个,
- 解耦:原函数只需关注核心逻辑,额外功能由装饰器处理。
- 复用:装饰器可被多个函数共享,避免重复代码。
9.2 基础装饰器结构
# 装饰器函数,fn 是被装饰的目标函数
def wrapper(fn): def inner():# 目标函数执行前的逻辑(如日志)print("在目标函数执行之前....") # 执行目标函数fn() # 目标函数执行后的逻辑(如统计)print("在目标函数执行之后....") # 返回内层函数,替代原函数return inner
9.3 装饰器用法与示例
场景:给游戏函数添加“开挂”和“关闭外挂”的日志
# 装饰器:给游戏函数添加额外逻辑
def guanjia(game): def inner():print("打开游戏加速器")# 执行原游戏函数game() print("关闭游戏加速器")return inner# 原函数 1
def play_dnf(): print("dnf游戏进程ing!")# 原函数 2
def play_lol(): print("lol游戏进程ing!")# 用装饰器增强函数
play_dnf = guanjia(play_dnf)
play_lol = guanjia(play_lol) # 调用增强后的函数
play_dnf()
play_lol()
输出:
语法糖简化:@
符号
装饰器还可通过 @
语法糖简化,效果与手动赋值一致:
def guanjia(game):def inner():print("打开游戏加速器")game()print("关闭游戏加速器")return inner# 语法糖:直接用 @ 装饰函数
@guanjia
def play_dnf():print("dnf游戏进程ing!")@guanjia
def play_lol():print("lol游戏进程ing!")# 直接调用,效果相同
play_dnf()
play_lol()
9.4 装饰器的典型应用场景
一般常用于以下三种场景,记录函数调用时间、参数等日志记录;调用函数前检查用户是否登录的权限校验;统计函数执行耗时的性能统计。
9.5 知识关联总结
知识点 | 核心作用 | 典型场景 |
---|---|---|
global | 局部作用域中操作全局变量 | 全局配置修改 |
nonlocal | 嵌套函数中操作外层局部变量 | 闭包变量修改 |
闭包 | 让变量常驻内存,实现数据持久化 | 计数器、状态保持 |
装饰器 | 不修改原函数,动态添加功能 | 日志、权限、性能统计 |
10.小结
本文系统介绍了Python函数的相关知识。从基础层面出发,详细讲解了函数参数的分类、实参传递方式以及函数返回值的特性,同时也介绍了进制转换的方法。
在高级特性部分,探讨了函数的嵌套定义、作为返回值和参数传递等用法,作用域、闭包和装饰器等概念的讲解并给出相应程序示例,
通过本文的学习,希望读者能够对Python函数有一个全面的认识,在实际编程中更加熟练地运用。