在Python中,函数是一个非常重要的概念,它允许将一段代码封装起来,以便在需要时重复调用。 函数相关的示例代码如下:
# 基础函数定义
# def 关键字定义函数,return 返回值。
# 文档字符串("""...""")用于说明函数功能。
def greet(name):
"""返回问候语(文档字符串)"""
return f"Hello, {name}!"
print(greet("Alice")) # 输出: Hello, Alice!
# 定义一个简单的函数,用于计算两个数的和
# def 关键字用于定义函数,后面紧跟函数名 add_numbers,括号内是函数的参数 a 和 b,冒号表示函数定义的开始。
# 函数体是缩进的代码块,这里使用 return 语句返回计算结果。
def add_numbers(a, b):
return a + b
# 调用函数
# 调用函数时,将实际参数 3 和 5 传递给函数,函数执行并返回结果,最后将结果存储在 result 变量中并打印。
result = add_numbers(3, 5)
print("两数之和为:", result) # 输出:两数之和为: 8
# 参数类型
# 默认参数的值在函数定义时计算一次,避免使用可变对象(如列表)作为默认值。
def power(base, exponent=2):
"""计算 base 的 exponent 次方,默认平方"""
return base ** exponent
# 使用默认 exponent=2
print(power(3)) # 输出:9
# 覆盖默认参数
print(power(3, 4)) # 输出:81
# 定义一个带有默认参数的函数
# 在函数定义中,greeting="Hello" 为参数 greeting 指定了默认值
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
# 调用函数时不提供第二个参数
message1 = greet("Alice")
print(message1) # 输出:Hello, Alice!
# 调用函数时提供第二个参数
message2 = greet("Bob", "Hi")
print(message2) # 输出:Hi, Bob!
# *args 是可变参数,它允许函数接受任意数量的位置参数。这些参数会被封装成一个元组。
# 在函数内部,可以像处理普通元组一样遍历 args 并进行计算。
def sum_all(*args):
"""计算任意数量参数的和"""
return sum(args)
print(sum_all(1, 2, 3)) # 输出:6
# **kwargs 接收任意数量的关键字参数(字典形式)。
def print_info(**kwargs):
"""打印关键字参数"""
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Bob", age=30) # 输出:name: Bob \n age: 30
# 定义一个接受可变数量参数的函数
def sum_numbers(*args):
total = 0
for num in args:
total += num
return total
# 调用函数
result1 = sum_numbers(1, 2, 3)
result2 = sum_numbers(1, 2, 3, 4, 5)
print("结果 1:", result1) # 输出:结果 1: 6
print("结果 2:", result2) # 输出:结果 2: 15
# 定义一个接受可变参数的函数
def print_args(*args, **kwargs):
for arg in args:
print(f"Positional argument: {arg}")
for key, value in kwargs.items():
print(f"Keyword argument: {key} = {value}")
# 调用函数,传递多个位置参数和关键字参数
print_args(1, 2, 3, a="x", b="y")
# 上面的代码调用print_args后输出如下:
# Positional argument: 1
# Positional argument: 2
# Positional argument: 3
# Keyword argument: a = x
# Keyword argument: b = y
# 作用域规则:
# 局部变量(函数内定义) > 外层函数变量(闭包) > 全局变量 > 内置变量。
# global 声明全局变量,nonlocal 声明闭包外层变量。
def outer():
x = 100
def inner():
nonlocal x # 声明非局部变量
x += 1
return x
return inner
# closure = outer() 这行代码调用了 outer 函数,而 outer 函数返回了 inner 函数对象。
# 所以 closure 实际上是一个指向 inner 函数的引用,也就是一个闭包对象。
# 此时,closure 就相当于一个变量,它存储的是 inner 函数的引用,而不是 inner 函数执行后的结果。
closure = outer()
print(closure) # 打印函数对象本身的信息,通常是函数对象在内存中的地址和函数名称等内容,输出:<function outer.<locals>.inner at 0x000001641458B380>
# 在 Python 中,要调用一个函数并获取其返回值,需要在函数对象后面加上一对括号 ()。
# 当使用 closure() 时,实际上就是在调用 inner 函数。
print(closure()) # 闭包保留外层变量状态,输出:101
# 定义一个全局变量
# 在下面的代码中,count 是一个在函数外部定义的全局变量。
# increment 函数使用 global 关键字来声明它要修改的是这个全局变量,而不是创建一个同名的局部变量。
count = 0
def increment():
# 使用 global 关键字声明我们要在函数内部修改的是全局变量 count
global count
count += 1
print(f"Inside increment: count = {count}")
def print_count():
# 直接访问全局变量 count,不需要使用 global 关键字(因为我们不修改它)
print(f"Inside print_count: count = {count}")
# 调用函数以演示全局变量的使用
increment() # 输出: Inside increment: count = 1
print_count() # 输出: Inside print_count: count = 1
increment() # 输出: Inside increment: count = 2
print_count() # 输出: Inside print_count: count = 2
x = 10 # 全局变量
def modify():
global x
x = 20 # 修改全局变量
y = 5 # 局部变量
modify()
print(x) # 输出 20
# 返回值
# 函数可以返回多个值(实际上是返回一个元组)。
def min_max(numbers):
return min(numbers), max(numbers) # 返回元组
result = min_max([4, 2, 9, 7])
print(result) # 输出 (2, 9)
# 可通过解包接收:low, high = min_max(...)
low, high = min_max([8, 3, 5, 9])
print(f"low:{low}") # 输出:low:3
print(f"high:{high}") # 输出:high:9
# lambda函数
squareLx = lambda lx: lx ** 2
print(squareLx(5)) # 输出 25
# 常用于排序等场景
# pairs = [(1, 'one'), (3, 'three'), (2, 'two')] 创建了一个列表 pairs,其中每个元素都是一个包含两个元素的元组。
# 元组的第一个元素是整数,第二个元素是字符串。
pairs = [(1, 'one'), (3, 'three'), (2, 'two')]
# 使用列表的 sort 方法对 pairs 列表进行排序,sort 方法的 key 参数用于指定一个函数,该函数将被应用到列表的每个元素上,以生成比较的键。
# 匿名函数(lambda 函数)lambda pair: pair[0]。这个匿名函数接受一个参数 pair(代表列表中的每个元组),并返回该元组的第一个元素。
pairs.sort(key=lambda pair: pair[0])
print(pairs) # 输出 [(1, 'one'), (2, 'two'), (3, 'three')]
# 装饰器
# 外层函数 logger:它接受一个函数 func 作为参数,这个函数就是要被装饰的目标函数。
def logger(func):
# *args 和 **kwargs 是 Python 中用于收集所有位置参数和关键字参数的语法。
# 这使得 wrapper 函数可以接受任意数量和类型的参数,从而可以无缝地传递给被装饰的函数 func。
def wrapper(*args, **kwargs):
# 在调用被装饰函数之前,wrapper 函数打印出被调用函数的名称,这实现了日志记录的功能。
print(f"调用函数: {func.__name__}")
# 调用被装饰的函数 func,并将从外部接收的参数 *args 和 **kwargs 原封不动地传递给它,然后返回 func 的执行结果。
return func(*args, **kwargs)
# 返回值:logger 函数最终返回 wrapper 函数对象。这意味着当一个函数被 @logger 装饰时,实际上是被替换为了 wrapper 函数。
return wrapper
# @logger 装饰器语法:这是 Python 中应用装饰器的简洁语法。
# 当解释器遇到 @logger 时,它会自动将下面定义的函数 add 作为参数传递给 logger 函数,并将 logger 函数的返回值(即 wrapper 函数)重新赋值给 add。
@logger
# add函数它接受两个参数 a 和 b,并返回它们的和。
# 但由于被 @logger 装饰,在调用 add 函数时,实际执行的是 wrapper 函数的逻辑,而 wrapper 函数会在调用 add 函数前后添加日志记录功能。
def add(a, b):
return a + b
print(add(2, 3)) # 先打印 "调用函数: add",换行再输出 5
# -> str 表示返回值类型为字符串。
def greet(name: str) -> str:
return f"Hello, {name}!"
print(greet("Jim"))
# 生成器函数
def count_up_to(max1):
count1 = 1
while count1 <= max1:
# yield count 这是生成器的关键语句。yield 语句会暂停函数的执行,并返回 count 的值。
# 与 return 不同,yield 会记住函数暂停的位置,下次调用 next() 时,函数会从暂停的地方继续执行。
# 使用 yield 关键字生成值,函数返回生成器对象。适合处理大数据流,按需生成值。
yield count1
count1 += 1
# gen = count_up_to(3) 调用 count_up_to 函数并传入参数 3,这并不会立即执行函数中的循环,而是返回一个生成器对象 gen。
# 生成器对象是可迭代的,并且可以通过 next() 函数来逐个获取生成的值。
gen = count_up_to(3)
# 第一次调用 next(gen) 时,生成器函数 count_up_to 开始执行,直到遇到第一个 yield count 语句。
# 此时,函数暂停并返回 count 的值 1,所以输出 1。
print(next(gen)) # 输出 1
# 第二次调用 next(gen) 时,生成器函数从上次暂停的位置(yield count 之后)继续执行,即执行 count += 1,此时 count 的值变为 2。
# 然后再次遇到 yield count,函数又暂停并返回 count 的值 2,所以输出 2。
print(next(gen)) # 输出 2
print(next(gen)) # 输出 3
# 如果第四次调用next,则count <= max 条件不成立,循环结束,生成器会引发 StopIteration 异常,因为已经没有更多的值可以生成了。
print(next(gen)) # 抛出 StopIteration
# 可以使用try except抛出异常
try:
print(next(gen))
except StopIteration:
print("catch stop iteration")
gen1 = count_up_to(3)
# for循环会自动捕获StopIteration异常并结束循环,不需要显式地进行异常处理。
for num in gen1:
print(f"using loop avoid stopIteration:{num}")
从以上的示例代码可以知道, 函数通过 def 定义,支持参数、返回值、嵌套定义。 参数类型灵活,支持默认参数、可变参数和关键字参数。 作用域规则需注意 global 和 nonlocal 的使用。 高级功能如装饰器、lambda、生成器等可简化代码逻辑。