9 函数
本篇是 Python 系列教程第 9 篇,更多内容敬请访问我的 Python 合集
1 定义函数
在 Python 中,你可以使用 def
关键字来定义一个函数。函数定义的基本语法如下:
def function_name(parameters):
# 函数体
# ...
return value
function_name
: 函数的名称。parameters
: 函数接受的参数列表。参数是可选的。return
: 可选的关键字,用于返回函数的结果。如果没有显式返回值,默认返回None
。
1.1 示例:定义一个简单的函数
下面是一个简单的函数示例,该函数接收两个参数并返回它们的和:
def add_numbers(a, b):
result = a + b
return result
# 调用函数
sum = add_numbers(5, 3)
print(sum) # 输出 8
1.2 示例:使用递归函数
递归函数是在函数内部调用自身的函数。下面是一个计算阶乘的递归函数示例:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
result = factorial(5)
print(result) # 输出 120
2 参数
函数可以接受不同类型的参数,包括位置参数、默认参数、关键字参数和可变参数。
2.1 位置参数
位置参数是根据参数在函数调用中的位置来确定的。
def greet(name):
print("Hello, " + name)
greet("Alice") # 输出 "Hello, Alice"
2.2 默认参数
默认参数允许你在定义函数时为参数设置默认值。
def greet(name, greeting="Hello"):
print(greeting + ", " + name)
greet("Alice") # 输出 "Hello, Alice"
greet("Bob", "Hi") # 输出 "Hi, Bob"
2.3 关键字参数
关键字参数允许你通过参数名称来传递值,这使得函数调用更加清晰。
def describe_person(name, age, occupation):
print(f"{name} is {age} years old and works as a {occupation}.")
describe_person(name="Alice", age=30, occupation="Engineer")
2.4 可变参数
可变参数允许你在不知道确切参数数量的情况下定义函数。
- 使用星号 (
*args
): 接收任意数量的位置参数。 - 使用双星号 (
**kwargs
): 接收任意数量的关键字参数。
def concatenate_strings(*args):
result = ""
for arg in args:
result += arg
return result
concatenated = concatenate_strings("Hello", " ", "world!")
print(concatenated) # 输出 "Hello world!"
def describe_person(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
describe_person(name="Alice", age=30, occupation="Engineer")
3 作用域
在 Python 中,函数作用域是指在函数内部定义的变量的作用范围。作用域规定了变量的可见性和生命周期。理解作用域对于编写清晰和高效的代码非常重要。下面是一些关于 Python 中作用域的基本概念:
3.1 局部作用域 (Local Scope)
局部作用域指的是在函数内部定义的变量的作用范围。这些变量仅在函数内部可用,并且在函数执行完毕后就会被销毁。
示例:
def my_function():
x = 10 # x 是局部变量
print(x) # 输出 10
my_function()
# print(x) # 如果在这里尝试访问 x,将会抛出 NameError,因为 x 是局部变量
3.2 全局作用域 (Global Scope)
全局作用域是指在整个程序范围内定义的变量的作用范围。这些变量可以在程序的任何地方访问,除非它们被局部作用域中的同名变量所遮蔽。
示例:
x = 5 # x 是全局变量
def my_function():
print(x) # 访问全局变量 x
my_function()
print(x) # 输出 5
3.3 内嵌作用域 (Enclosing Scope)
当一个函数内部定义了另一个函数时,内部函数可以访问外部函数的局部变量,这种情况称为内嵌作用域。
示例:
def outer_function():
x = 30 # x 是 outer_function 的局部变量
def inner_function():
print(x) # 访问外部函数的局部变量 x
inner_function()
outer_function()
3.4 内建作用域 (Built-in Scope)
Python 自带了一些预定义的全局变量和函数,例如 len()
、print()
等。这些都位于内建作用域中,可以在程序的任何地方访问。
3.5 LEGB 规则
LEGB 是一个缩写词,代表 Local、Enclosing、Global 和 Built-in,这是 Python 中查找变量的作用域顺序:
- Local: 在当前函数的作用域中查找变量。
- Enclosing: 如果在当前函数中找不到变量,则向上一级函数的作用域中查找。
- Global: 如果在所有内嵌作用域中都找不到变量,则在全局作用域中查找。
- Built-in: 最后,在内建作用域中查找。
3.6 nonlocal
和 global
关键字
nonlocal
和 global
关键字用于声明变量的作用域。
nonlocal
: 用于声明变量属于最近一个拥有该变量的内嵌作用域。从字面意思“非本地”就能理解并不是本层的。global
: 用于声明一个变量属于全局作用域。
示例:
x = 50 # 全局变量
y = 50 # 全局变量
def outer_function():
x = 100 # outer_function 的局部变量
y = 100 # outer_function 的局部变量
def inner_function():
nonlocal x # 声明 x 是 outer_function 的局部变量
x = 200 # 修改 outer_function 的局部变量 x
print("Inner x:", x) # 输出 200
global y # 声明 y 是 全局变量
print("Inner y:", y) # 输出 50
inner_function()
# 访问 outer_function 的局部变量 x
print("Outer x:", x) # 输出 200
outer_function()
print("Global x:", x) # 输出 50
print("Global y:", y) # 输出 50
在这个例子中,inner_function
修改了 outer_function
中的 x
,而不是创建一个新的局部变量。inner_function
修改了全局的y
,而不是 outer_function
中的 y
3.7 总结
- 局部变量只在其定义的函数内部可见。
- 全局变量在整个程序中可见。
- 内嵌作用域允许内部函数访问外部函数的局部变量。
- 内建作用域包含了 Python 的预定义内置函数和变量。
- 内部函数修改外部函数的变量要先用
nonlocal
先声明;内部函数修改全局变量要先用global
声明。
4 常用内置函数
那可太多了,刚好凑字数(不是)
Python 提供了许多内置函数,这些函数可以帮助你执行各种常见的任务,而无需编写额外的代码。下面是一些常用的内置函数及其说明:
4.1 数据类型转换函数
这些函数用于将一种数据类型转换为另一种数据类型。
int()
: 将给定的值转换为整数。
int("42") # 结果是 42
float()
: 将给定的值转换为浮点数。
float("3.14") # 结果是 3.14
str()
: 将给定的值转换为字符串。
str(100) # 结果是 "100"
bool()
: 将给定的值转换为布尔值。
bool(1) # 结果是 True
list()
: 将给定的值转换为列表。
list("hello") # 结果是 ['h', 'e', 'l', 'l', 'o']
tuple()
: 将给定的值转换为元组。
tuple("hello") # 结果是 ('h', 'e', 'l', 'l', 'o')
set()
: 将给定的值转换为集合。
set("hello") # 结果是 {'h', 'e', 'l', 'o'}
dict()
: 将给定的键值对转换为字典。
dict([(1, "one"), (2, "two")]) # 结果是 {1: "one", 2: "two"}
4.2 控制流相关的函数
这些函数用于控制程序的执行流程。
abs()
: 返回数值的绝对值。
abs(-5) # 结果是 5
all()
: 如果**可迭代对象(说白了就是数组)**的所有元素都为True
,则返回True
;否则返回False
。
all([True, True, True]) # 结果是 True
any()
: 如果可迭代对象中至少有一个元素为True
,则返回True
;否则返回False
。
any([False, True, False]) # 结果是 True
enumerate()
: 返回一个枚举对象,可以同时获取索引和值。适用场景:处理列表、元组或字符串中的元素时,需要同时访问索引和值。
for index, char in enumerate("hello"):
print(index, char)
# 输出:
# 0 h
# 1 e
# 2 l
# 3 l
# 4 o
fruits = ["apple", "banana", "cherry", "date"]
for index, fruit in enumerate(fruits):
print(f"Index: {index}, Fruit: {fruit}")
# 输出
# 0 apple
# 1 banana
# 2 cherry
# 3 date
sorted()
: 对可迭代对象进行排序。
sorted([3, 1, 2]) # 结果是 [1, 2, 3]
reversed()
: 返回一个反转的迭代器。注意不能直接打印,需要遍历。
print(reversed([1, 2, 3]))
# 直接打印的花会输出 <list_reverseiterator object at 0x000001526CE4AAA0>
for x in reversed([1, 2, 3]):
print(x)
# 输出
# 3
# 2
# 1
zip()
: 将多个可迭代对象打包成一个元组的列表。
for x in zip([1, 2, 3], ['a', 'b', 'c']):
print(x)
# 输出
# (1, 'a')
# (2, 'b')
# (3, 'c')
4.3 数学相关的函数
这些函数用于执行基本的数学运算。
round()
: 四舍五入。
round(3.14) # 结果是 3
min()
: 返回可迭代对象中的最小值。
min([1, 2, 3]) # 结果是 1
max()
: 返回可迭代对象中的最大值。
max([1, 2, 3]) # 结果是 3
sum()
: 返回可迭代对象中的元素之和。
sum([1, 2, 3]) # 结果是 6
4.4 字符串相关的函数
这些函数用于处理字符串。
len()
: 返回对象的长度。
len("hello") # 结果是 5
str.join()
: 使用指定的分隔符连接字符串列表。
"-".join(["a", "b", "c"]) # 结果是 "a-b-c"
print()
: 打印输出。
print("Hello, world!") # 输出 "Hello, world!"
4.5 其他常用函数
type()
: 返回对象的类型。
type(10) # 结果是 <class 'int'>
id()
: 返回对象的标识符。
id(10) # 返回对象的唯一标识符
input()
: 从标准输入读取一行。
name = input("Enter your name: ")
help()
: 显示帮助文档。
help(len) # 显示 len 函数的帮助文档
dir()
: 列出对象的所有属性和方法。
dir("hello") # 列出字符串对象的方法和属性
eval()
: 评估一个字符串,并执行其中的 Python 表达式。
eval("1 + 2") # 结果是 3
exec()
: 动态执行 Python 代码。
exec("print('Hello, world!')") # 输出 "Hello, world!"
globals()
: 返回一个字典,其中包含了当前模块的全局变量及其值。
# 定义全局变量
x = 10
print(globals())
# 输出,可以在末尾看到变量x
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000017E8933BCB0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:\\PycharmProjects\\demo1\\Hello.py', '__cached__': None, 'x': 10}
globals()
函数主要用于以下几种情况:
- 动态访问全局变量:
# 定义全局变量 x = 10 y = 20 # 使用 globals() 访问全局变量 def access_globals(): global_var_x = globals()["x"] global_var_y = globals()["y"] print(global_var_x) # 输出 10 print(global_var_y) # 输出 20 access_globals()
- 检查全局命名空间的内容:
# 定义全局变量 x = 10 y = 20 # 检查全局命名空间的内容 def inspect_globals(): global_vars = globals() for key, value in global_vars.items(): print(key, ":", value) inspect_globals() # 输出 # __name__ : __main__ # __doc__ : None # __package__ : None # __loader__ : <_frozen_importlib_external.SourceFileLoader object at 0x000001EA9BCEBCB0> # __spec__ : None # __annotations__ : {} # __builtins__ : <module 'builtins' (built-in)> # __file__ : D:\PycharmProjects\demo1\Hello.py # __cached__ : None # x : 10 # y : 20 # inspect_globals : <function inspect_globals at 0x000001EA9BE684A0>
- 动态创建变量:
def create_variable(var_name, var_value): # 动态创建全局变量 globals()[var_name] = var_value create_variable("z", 30) print(z) # 输出 30
- 调试和开发:
在调试或开发过程中,
globals()
可以帮助你了解当前模块的状态。locals()
: 返回一个字典,其中包含了当前模块的局部变量及其值。作用和上面globals()
函数类似。
locals() # 返回局部变量的字典
callable()
: 检查一个对象是否可调用。
callable(print) # 结果是 True
isinstance()
: 检查一个对象是否为指定类的实例。
isinstance(10, int) # 结果是 True
getattr()
: 获取对象的属性。
getattr("hello", "__len__")() # 结果是 5,注意后面的()不能省
hasattr()
: 检查对象是否有指定的属性。
hasattr("hello", "__len__") # 结果是 True
setattr()
: 设置对象的属性。
class MyClass:
pass
obj = MyClass()
setattr(obj, "value", 10)
print(obj.value) # 输出 10
delattr()
: 删除对象的属性。
delattr(obj, "value")
map()
: 允许你对序列中的每个元素应用一个函数,并返回一个新的序列。
map(function, iterable, ...)
# function: 一个函数,将应用于每个元素。
# iterable: 一个或多个可迭代对象(如列表、元组等),其中的每个元素都将被传递给 function。
map()
函数返回一个 map
对象,这个对象是一个迭代器,你可以通过 list()
、tuple()
或者遍历来获取结果。关于迭代器(iterator)和可迭代对象(iterable)的区别和关系请移步文末。
list()
: 返回列表,用途包括:创建空列表。
将迭代器或任何类型可迭代对象转为列表。
复制列表。
函数有太多了,这里就不一一列举了。
5 lambda表达式
在 Python 中,lambda 表达式是一种创建小型匿名函数的方式。它允许你在一行代码内快速定义简单的函数,而无需使用标准的 def 关键字来定义函数。
5.1 语法
lambda arguments: expression
lambda
是用来声明表达式的关键词。arguments
一个或多个参数,它们之间用逗号 , 分隔。expression
一个有效的 Python 表达式,该表达式将被计算并作为 lambda 函数的结果返回。
5.2 注意事项
lambda
表达式通常用于简单的操作,如果逻辑较为复杂,建议使用传统的def
关键字定义函数。lambda
函数只能包含一个表达式,不能包含多行代码。
5.3 使用示例
让我们来看几个 lambda
表达式的例子:
5.3.1 简单的 lambda 函数
# 定义一个 lambda 函数,用于计算两个数的和
add = lambda x, y: x + y
# 调用 lambda 函数
result = add(5, 3)
print(result) # 输出: 8
5.3.2 使用 lambda 函数进行排序
假设我们有一个包含字典的列表,并且我们想按照字典中的某个键来进行排序:
people = [
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 22},
{'name': 'Charlie', 'age': 30}
]
# 使用 lambda 函数作为 key 参数对列表进行排序
sorted_people = sorted(people, key=lambda person: person['age'])
# 打印排序后的列表
for person in sorted_people:
print(person)
# 输出结果将根据age进行排序:
# {'name': 'Bob', 'age': 22}
# {'name': 'Alice', 'age': 25}
# {'name': 'Charlie', 'age': 30}
5.3.3 在高阶函数中使用 lambda
Python 中的 map()
, filter()
, reduce()
等函数都可以接受 lambda
函数作为参数。
- 使用
map()
函数(上面已经介绍map()
函数的功能):
numbers = [1, 2, 3, 4, 5]
squares = map(lambda x: x**2, numbers)
print(list(squares)) # 输出: [1, 4, 9, 16, 25]
- 使用
filter()
函数(功能是过滤值):
numbers = [1, 2, 3, 4, 5]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers)) # 输出: [2, 4]
- 使用
reduce()
函数(功能是做累积)需要导入functools
模块:
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # 输出: 120
拓展:
迭代器(iterator)和可迭代对象(iterable) 是两个紧密相关的概念,它们都能实现循环遍历。通常通过调用可迭代对象的 __iter__
方法来创建迭代器。
下面是一个简单的例子,演示如何使用可迭代对象和迭代器:
# 定义一个可迭代对象(列表)
my_list = [1, 2, 3, 4, 5]
# 获取该可迭代对象的迭代器,两种方式均可
# iterator = iter(my_list)
iterator = my_list.__iter__()
# 使用迭代器遍历列表
while True:
try:
item = next(iterator)
print(item)
except StopIteration:
break
Q: 可迭代对象有哪些?
A: 很多,列表(List)、元组(Tuple)、字典(Dictionary)、集合(Set)、甚至字符串(String)、范围(Range)都是。
Q: 如何创建迭代器?
A: 使用 iter() 和 next() 方法。