目录
一、函数是什么?
函数是一段封装了特定功能可重复执行的的代码块。
二、函数定义
用def定义一个函数,具体的语法结构如下:
def 函数名(参数1, 参数2, ...):
"""文档字符串(可选)"""
函数体
return 返回值 # 可选
def:声明一个函数。
函数名:给函数起的一个名字。
注释:针对下面的代码块所给予的解释性说明。
函数体:实现函数功能的一段代码块。
return:返回函数的结果,没有则返回None。
注意:一旦执行力return,就代表着函数执行结束,后续代码块也就不会执行。
三、函数调用
当定义好一个函数后,需要通过调用来实现这一代码块的功能。下面是一个打招呼的问候函数,具体代码示例如下:
def greet(name):
"""向指定的人问好"""
return f"Hello, {name}!"
#调用函数,实现其功能。
message = greet("Alice")
print(message) # 输出: Hello, Alice!
调用函数的格式是:函数名()。函数有返回值的,通过print()打印出函数的返回值。
四、参数类型
1.位置参数
位置参数必须按照位置的顺序赋值,不能忽略任何一个参数。
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("Alice", "Hello") # 正确:按顺序传参
greet("Hello", "Alice") # 错误:顺序不对,逻辑错误
2.默认参数
定义函数时,在小括号内指定某个参数,给其赋给一个默认值。
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Alice") # 使用默认值 "Hello"
greet("Bob", "Hi") # 覆盖默认值
两点注意:如果传入有实参,则使用实参;默认参数必须放在位置参数之后,否则会报错。
3.关键字参数
在传入实参的括号内,以“参数=值”的形式传参,顺序可以打乱;有默认参数时,会覆盖默认参数,使用关键字参数。
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet(greeting="Hi", name="Alice") # 关键字传参,顺序不影响
4.可变参数
(1)元组类型(*args)
可以接收任意数量的位置参数,以元组的形式保存起来。
def sum_numbers(*args):
return sum(args)
print(sum_numbers(1, 2, 3)) # 6
print(sum_numbers(1, 2, 3, 4, 5)) # 15
(2)字典类型(**kwargs)
可以接收任意数量的关键字参数(参数=值的形式),以字典的形式保存起来。重要的是二者的先后顺序是:按照*args在前,**kwargs在后的先后顺序排列。
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=25, city="New York")
#输出:
#name: Alice
#age: 25
#city: New York
五、返回值
三点描述:
- 1.返回值通过return返回。
- 2.可以返回多个值,实际上是返回一个元组。
- 3.函数中return,或者return没有值,都是返回空值None。
def min_max(numbers):
return min(numbers), max(numbers)
print(min_max([3, 1, 4, 1, 5, 9]))#输出:(1, 9)
上述函数的输出结果是元组,因为返回的有多个值。
六、递归函数
递归函数是指在函数定义中调用自身的函数,是解决某些问题的强大工具。递归通过将问题分解为更小的同类子问题来工作。
经典案例:斐波那契数列
def fibonacci(n):
if n == 1 or n == 2: # 基线条件
return 1
else: # 递归条件
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(7)) # 输出: 13
提出的几点注意:
- 自己调用自己
- 需要有出口
- 递归效率很低,一般不使用递归。
如果想查看或者修改递归深度,可以使用sys模块。
from sys import getrecursionlimit, setrecursionlimit
print(getrecursionlimit())#1000
setrecursionlimit(1200)
print(getrecursionlimit())#1200
七、匿名函数
1.语法结构
lambda 参数 : 函数体
lambda:定义匿名函数的关键字
参数:可以有多个,用逗号分隔
函数体:只能是一个表达式(不能是语句)
例如:计算两个数的和,add()是一个函数,通过print()返回值。
# 定义一个计算两数之和的lambda函数
add = lambda a, b: a + b
print(add(3, 4)) # 输出: 7
2.形式
(1)无参,无返回值
my_fun1 = lambda: print("上课铃响了")
my_fun1()
my_fun1这个函数没有参数,也没有返回值,输出的结果是“上课铃响了”。
(2)无参,有返回值
myfun3 = lambda : 15
print(myfun3())
my_fun2这个函数没有参数,但是有返回值,将常量15返回出来了。
(3)有参,有返回值
a = [1, 2, 3, 4, 5]
my_fun2 = lambda a: [i*i for i in a]
r = my_fun2(a)
print(r)
my_fun3这个函数有参数,有返回值,将参数a这个列表传入匿名函数,结果可以得到新的列表。
(4)有参,无返回值
myfun4 = lambda x: print(f"数字是{x}")
myfun4(9)
my_fun4这个函数有参数,没有返回值,将参数x=9传入匿名函数,通过print()打印结果输出9。
3.高阶函数
(1)sorted函数
sorted( ):对可迭代对象进行排序并返回新列表,支持自定义排序规则。
结构:sorted(可迭代对象, key=匿名函数)
students = [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 18},
{"name": "Charlie", "age": 22}
]
sorted_student = sorted(students, key=lambda x: x["age"])
print(sorted_student)
这个案例的功能是对字典排序,其中用匿名函数指出使用“age”关键字进行排序。
(2)map函数
map( ):将函数应用于可迭代对象的每个元素,返回包含结果的迭代器。
结构:map(匿名函数,可迭代对象)
l = [1, 5, 7, 3, 9]
maped_l = map(lambda x: x+1, l)
print(type(maped_l))# <class 'map'> map对象
for i in maped_l:
print(i)
本案例map函数的数据类型是map类性,需要进一步的遍历得出每一个结果。
(3)filter函数
filter( ) : 用指定函数过滤可迭代对象,返回满足条件的元素组成的迭代器。
结构:filter(匿名函数, 可迭代对象)
students = [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 18},
{"name": "Charlie", "age": 22}
]
filtered_student = filter(lambda x: x["age"] == 18, students)
print(type(filtered_student))# <class 'filter'>filter对象
for j in filtered_student:
print(j)
filter()函数的类型是filter,其结果也需要进一步的遍历。本例功能是指出age=18,遍历出其对应的字典。
八、变量作用域
1.局部变量
函数内部定义的变量,仅在函数内部可见
def my_func():
x = 10 # 局部变量
print(x)
my_func() # 输出: 10
print(x) # 报错: NameError
2.全局变量
在模块级别定义的变量,整个模块都可见
y = 20 # 全局变量
def my_func():
print(y) # 可以访问全局变量
my_func() # 输出: 20
print(y) # 输出: 20
3.修改全局变量
在需要修改全局变量时显式使用 global
关键字
count = 0
def increment():
global count # 声明使用全局变量
count += 1
increment()
print(count) # 输出: 1
4.在嵌套函数中修改外层变量
在嵌套函数中修改外层变量时使用 nonlocal
关键字
def outer():
x = "outer"
def inner():
nonlocal x # 声明使用外层函数的变量
x = "inner"
print(x) # 输出: inner
inner()
print(x) # 输出: inner
outer()
5.LEGB规则
-
局部作用域(Local) - 在函数内部定义的变量
-
闭包函数外的函数作用域(Enclosing) - 嵌套函数中的外层函数变量
-
全局作用域(Global) - 在模块级别定义的变量
-
内置作用域(Built-in) - Python内置的变量(如
print
,len
等)
九、闭包与装饰器
1.闭包
闭包是指在一个内部函数中访问其外部函数作用域中的变量,即使外部函数已经执行完毕。
三要素:
- 1.外部函数嵌套内部函数
- 2.外部函数返回内部函数
- 3.内部函数可以访问保存外部函数的局部变量。
def outer_fun():
x = 20
def inner_fun():
nonlocal x
x += 10
y = 10
print(x, y)
return inner_fun # 注意此处是返回函数对象,而不是返回整个函数。
r = outer_fun()
# print(r)# <function outer_fun.<locals>.inner_fun at 0x000001CBEB0A3BA0>,说明r是函数
r()# 30 10
r()# 40 10
r()# 50 10 内部函数可以访问保存外部函数的局部变量
2.装饰器
装饰器是一种特殊类型的闭包,用于修改或增强函数的行为而不改变其原始定义。
2.1.语法结构
闭包+@语法
2.2.案例
2.2.1.时间开销
编写装饰器统计使用冒泡排序与选择排序时间开销
import random, time
def time_cost(fun):
def calc():
start = time.time()
fun()
end = time.time()
print(f"{fun.__name__}累计耗时{end - start}")
return calc
@time_cost
def sort1():
l = [random.randint(1, 100) for i in range(100)]
l.sort()
print(l)
sort1()
@time_cost
def sort2():
l = [random.randint(1, 100) for i in range(100)]
t = sorted(l)
print(t)
sort2()
@time_cost
def sort3():
l = [random.randint(1, 100) for i in range(100)]
for i in range(1, len(l)):
for j in range(0, len(l)-i):
if l[j] > l[j+1]:
l[j], l[j+1] = l[j+1], l[j]
print(l)
sort3()
@time_cost
def sort4():
l = [random.randint(1, 100) for i in range(100)]
for i in range(len(l) - 1):
max_index = i
for j in range(i+1, len(l)):
if l[j] < l[max_index]:
max_index = j
l[max_index], l[i] = l[i], l[max_index]
print(l)
sort4()
2.2.2.权限校验
下面是登录界面的权限校验。
from functools import wraps
user = None
def login(fun):
@wraps(fun)
def check():
global user
if user is not None:
fun()
else:
username = input("请输入用户名:")
password = input("请输入密码:")
if username == "user" and password == "123456":
user = username
fun()
else:
print("未成功登陆,请重新验证!")
return check
def my_main():
print("欢迎来到主页")
my_main()
@login
def my_login():
print("欢迎来到个人中心")
my_login()
@login
def my_cart():
print("欢迎来到购物车")
my_cart()
2.2.3.日志记录
通过装饰器,对功能函数的运行时间、参数、函数名以及返回值进行记录。
from datetime import datetime
def my_log(fun):
def inner_log(*args):
t = fun(*args)
with open("record.log", "a", encoding="utf8") as f:
msg = f"时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} 函数名:{fun.__name__} 参数:{args} 返回值:{t}"
f.write(f"{msg}\n")
return t
return inner_log
@my_log
def get_sum(a, b):
total = a + b
return total
print(get_sum(5, 7))
总结
函数是编程中用于封装特定功能的可重用代码块,通过定义和调用来实现模块化编程。定义函数使用`def`关键字,后接函数名、参数列表和冒号,函数体需缩进。调用函数时通过函数名加括号传入实际参数即可执行函数体代码。参数分为位置参数、关键字参数、默认参数和可变参数(`*args`和`**kwargs`),灵活适应不同调用需求。函数通过`return`返回值,若无返回则默认`None`。递归函数通过调用自身解决问题,需设置终止条件防止无限递归。匿名函数(`lambda`)用于简化小型函数定义,格式为`lambda 参数:表达式`。变量作用域分局部(函数内)和全局(函数外),局部变量优先,全局变量需用`global`声明修改。闭包是嵌套函数中内层函数引用外层变量,常用于保存状态;装饰器基于闭包实现,通过`@`语法通常在不修改原函数代码前提下扩展功能,如日志、计时等。这些特性共同构成Python函数编程的核心,提升代码的复用性、可读性和灵活性。