Python函数编程
函数的基本使用
在Python中,函数是一段可重复使用的代码块,用于执行特定的任务或完成特定的操作。函数能够接受输入参数,执行特定的逻辑,并返回一个结果。下面是函数的一些重要知识点:
定义与调用
- 函数的定义使用关键字
def
,后面跟着函数名、参数列表和冒号。函数体在缩进块中。 - 函数的调用通过函数名加括号的形式实现。
def greet(name):
print("Hello, " + name)
greet("Alice") # 调用函数 greet,输出:Hello, Alice
函数的参数
- 形式参数(形参):在函数定义时用来接收传入的值的参数。可以是必需参数或可选参数。
- 实际参数(实参):在函数调用时传递给函数的值。
- 函数可以有多个参数,包括位置参数、默认参数和可变参数。
def add(x, y): # 位置参数
return x + y
def greet(name, greeting="Hello"): # 默认参数
print(greeting + ", " + name)
def multiply(*nums): # 可变参数
result = 1
for num in nums:
result *= num
return result
sum = add(3, 5) # 调用函数 add,返回 8
greet("Alice") # 调用函数 greet,输出:Hello, Alice
greet("Bob", "Hi") # 调用函数 greet,输出:Hi, Bob
product = multiply(2, 3, 4) # 调用函数 multiply,返回 24
关键字参数的定义和使用
关键字参数主要体现在函数调用时,可以通过参数名=值的形式传递关键字参数:
def greet(name, message="Hello"):
print(message + ", " + name)
greet("Alice") # 使用默认参数,输出:Hello, Alice
greet("Bob", message="Hi") # 使用关键字参数,输出:Hi, Bob
greet(message="Hey", name="Carol") # 顺序不影响,输出:Hey, Carol
注意:函数调⽤时,如果有位置参数时,位置参数必须在关键字参数的前⾯,但关键字参数之间不存在先后顺序。
可变参数中的*和**
可变参数允许函数接受不定数量的参数,分为两种类型:可变位置参数和可变关键字参数
- *用于接收可变数量的位置参数,将其打包为一个元组
- **用于接收可变数量的关键字参数,将其打包为一个字典
def multiply(*nums):
result = 1
for num in nums:
result *= num
return result
def print_info(**kwargs):
for key, value in kwargs.items():
print(key + ": " + value)
product = multiply(2, 3, 4) # 接收多个位置参数,返回 24
print_info(name="Alice", age="25") # 接收多个关键字参数,输出 name: Alice, age: 25
参数的传递方式
在Python中,函数参数的传递方式可以分为值传递和引用传递。理解函数参数的传递方式很重要,因为它涉及到函数对参数的修改是否会影响原始数据。
下面是关于值传递和引用传递的详细介绍以及相关的注意事项(准确来说我们应该关注可变对象和不可变对象在作为函数参数传递时的不同表现):
值传递(Pass by Value):
值传递是指将实际参数的值复制一份,传递给函数的形式参数。在函数内部对形式参数的修改不会影响原始数据。
值传递适用于不可变对象,如数字、字符串和元组等。
def change_value(num): num = 10 value = 5 change_value(value) print(value) # 输出:5,原始数据不受函数修改影响
引用传递(Pass by Reference):
引用传递是指将实际参数的引用(内存地址)传递给函数的形式参数。在函数内部对形式参数的修改会影响原始数据。
引用传递适用于可变对象,如列表、字典和集合等。
def change_list(lst): lst.append(4) my_list = [1, 2, 3] change_list(my_list) print(my_list) # 输出:[1, 2, 3, 4],原始数据受函数修改影响
注意事项:
- 对于不可变对象(如数字、字符串、元组),函数内部对形式参数的修改不会影响原始数据。
- 对于可变对象(如列表、字典、集合),函数内部对形式参数的修改会影响原始数据。
- 在函数内部,可以通过赋值操作来创建新的可变对象,以避免影响原始数据。
- 在函数调用时,传递不可变对象的值本身,并不会改变原始数据的值。
- 在函数调用时,传递可变对象的引用,函数内部对引用进行操作会改变原始数据的内容。
关于值传递和引用传递
有人可能会说Python只有引用传递是因为在Python中,函数的参数传递方式确实是通过传递对象的引用(内存地址)来实现的。这种传递方式被称为引用传递(Pass by Reference)。
Python中的对象包括可变对象(如列表、字典、集合)和不可变对象(如数字、字符串、元组)。对于不可变对象,虽然函数内部对形式参数的修改不会影响原始数据,但仍然是通过传递对象的引用来实现的。对于可变对象,函数内部对形式参数的修改会影响原始数据,也是通过传递对象的引用来实现的。
这种通过传递对象引用的方式,使得函数可以直接操作原始数据,而无需进行大量的数据复制,从而提高了程序的执行效率。同时,这也符合Python的设计理念,即一切皆对象,一切都是引用。
然而,需要注意的是,虽然Python中的函数参数传递方式是通过引用传递,但在实际使用中,我们仍然需要区分可变对象和不可变对象的影响。对于不可变对象,函数的操作不会改变原始数据的值;对于可变对象,函数的操作会改变原始数据的内容。因此,可以将Python的参数传递方式看作是一种“引用传递的副作用”。
总结起来,尽管Python中的参数传递方式是通过引用传递来实现的,但我们真正需要注意的是不可变对象和可变对象在作为函数参数传递的过程中所受到的的影响,以编写正确的代码并避免出现意外的副作用。
作用域和变量
- 函数内部可以访问外部作用域的变量,但不能直接修改外部作用域的变量(除非使用
global
关键字)。 - 局部变量是在函数内部定义的变量,只在函数内部可见。
- 全局变量是在函数外部定义的变量,可以在整个程序中访问。
def greet():
message = "Hello" # 局部变量
print(message
name = "Alice" # 全局变
greet() # 调用函数 greet,输出:Hello
print(name) # 输出:Alice
函数的返回值
- 函数可以使用
return
语句返回一个值。如果函数没有明确的返回语句,将返回None
。 - 可以返回单个值、多个值(以元组形式返回)、或者使用关键字参数返回字典。
def add(x, y):
return x + y
def divide(dividend, divisor):
quotient = dividend // divisor
remainder = dividend % divisor
return quotient, remainder
def get_info():
return {"name": "Alice", "age": 25}
sum = add(3, 5) # 调用函数 add,返回 8
result = divide(10, 3) # 调用函数 divide,返回 (3, 1)
info = get_info() # 调用函数 get_info,返回 {"name": "Alice", "age": 25}
Python函数文档
在Python中,函数文档是用于描述函数的目的、输入参数、输出结果和使用方法的字符串。它提供了函数的说明和使用示例,帮助其他开发者理解和正确使用函数。下面是详细介绍函数文档及相关注意事项的内容:
函数文档的编写:
- 函数文档通常位于函数定义的下一行,并使用三引号(
'''
或"""
)括起来。 - 函数文档应该清晰、简洁地描述函数的功能、输入参数、返回值和使用方法。
- 可以使用适当的标记和格式化方式,如段落、列表、代码块等,以提高可读性。
def add(x, y): """ 函数 add 实现了两个数相加的功能。 参数: x -- 第一个操作数 y -- 第二个操作数 返回值: 两个数的和 使用示例: result = add(3, 5) print(result) # 输出:8 """ return x + y
- 函数文档通常位于函数定义的下一行,并使用三引号(
使用
help()
函数查看函数文档:- Python提供了内置的
help()
函数,用于查看函数的文档字符串。 - 可以在交互式解释器或脚本中使用
help()
函数来获取函数的说明和使用示例。help(add) # 查看函数 add 的文档
- Python提供了内置的
注意事项:
- 函数文档是代码的重要组成部分,应当养成良好的编写函数文档的习惯。
- 函数文档应该提供足够的信息,以便其他开发者理解函数的用途和正确使用方式。
- 函数文档应该及时更新,以反映函数的最新变化和功能。
- 在编写函数文档时,可以考虑使用一些标准的文档约定和规范,如Google风格、Numpy风格等。
- 函数文档的编写是一种良好的编码实践,它可以提高代码的可维护性和可读性。
函数文档是Python代码中重要的注释和说明,它可以帮助开发者更好地理解和使用函数。合理编写函数文档有助于提高代码质量,促进团队协作和代码复用。
递归函数
递归函数是指在函数的定义中调用函数本身的过程。Python允许使用递归函数来解决一些需要重复执行相同操作的问题。下面是有关递归函数的详细介绍及相关的注意事项:
递归函数的定义:
在函数的定义中调用函数本身,以实现问题的分解和求解。
递归函数必须包含终止条件,即递归的停止条件,否则会陷入无限递归的循环中。
def factorial(n): if n == 0: # 终止条件 return 1 else: return n * factorial(n - 1) # 递归调用 result = factorial(5) # 计算 5 的阶乘,返回 120
递归函数的注意事项
- 确保递归函数具有合适的终止条件,以避免无限递归。
- 确保递归的问题规模在每次递归调用中都能减小,否则可能导致栈溢出或性能问题。
- 尽量使用递归函数解决问题时,需要权衡递归的性能和可读性,以确保代码的效率和可维护性。
- 递归函数在某些情况下可以提供简洁而优雅的解决方案,但在处理大规模问题时,可能会导致内存消耗过大。
- 递归函数的调用过程中会产生函数调用栈,每次函数调用都会将当前函数的局部变量和返回地址等信息保存在栈中,直到递归结束时依次弹出栈中的信息。
- 在某些情况下,迭代循环(循环结构)可能比递归函数更有效率和可读性更好。
递归函数在解决一些问题时非常有用,尤其是问题可以自然地分解成较小的子问题的情况。但是,需要小心处理递归的终止条件和问题规模的减小,以避免无限递归和性能问题。
在使用递归函数时,要根据具体情况进行权衡,并确保代码的正确性和可读性。
Lambda函数
Lambda函数是一种匿名函数,也称为"lambda表达式"。它是一种简洁的定义函数的方式,可以在需要函数的地方使用,并且不需要为函数命名。下面是有关Lambda函数的详细介绍及相关的注意事项:
Lambda函数的语法:
Lambda函数的语法格式为:
lambda 参数: 表达式
Lambda函数可以有多个参数,用逗号分隔。
表达式是函数的返回值,可以是任意有效的表达式。
# 计算两个数的和 add = lambda x, y: x + y result = add(3, 5) # 返回 8 # 判断一个数是否为偶数 is_even = lambda num: num % 2 == 0 even = is_even(6) # 返回 True
Lambda函数的特点:
- Lambda函数是一种匿名函数,不需要为函数命名,可以直接在需要的地方定义和使用。
- Lambda函数通常用于简单的函数操作,可以替代一些简单的函数定义。
- Lambda函数可以作为参数传递给其他函数,如高阶函数的参数。
- Lambda函数的定义比较简洁,适用于简单的函数逻辑,不适合复杂的函数定义。
注意事项
- Lambda函数的语法比较简洁,但由于它是一种匿名函数,可读性可能较差。适用于简单的函数操作,但对于复杂的逻辑,建议使用常规函数定义来提高可读性和维护性。
- Lambda函数通常用于临时函数的定义,如果需要在多个地方复用函数逻辑,还是应该使用常规函数定义。
- Lambda函数可以作为高阶函数的参数,用于传递简单的函数逻辑。这在函数式编程和某些特定场景下非常有用。
- Lambda函数不能包含复杂的语句,只能使用表达式,并且返回结果。如果需要复杂的逻辑和多行代码,应使用常规函数定义。
Lambda函数在某些情况下非常有用,特别是在需要简洁定义函数或传递简单函数逻辑的场景中。然而,需要根据具体的需求和复杂性,权衡Lambda函数的可读性和使用常规函数定义的可维护性。
Python高阶函数
在Python中,函数是一等公民,可以作为参数传递给其他函数,也可以作为另一个函数的返回值。这种方式常用于函数式编程和高阶函数的应用。
高阶函数是指接受一个或多个函数作为参数,并/或返回一个函数作为结果的函数。Python中支持高阶函数的特性,可以方便地进行函数的组合、转换和扩展。
def add(x, y):
return x + y
def apply_operation(operation, x, y):
return operation(x, y)
sum = apply_operation(add, 3, 5) # 调用函数 apply_operation,返回 8
下面将介绍python有关常用内置高阶函数的用例
map(func, iter)
map(function, iterable)
:将函数应用于可迭代对象的每个元素,并返回一个新的可迭代对象。
numbers = [1, 2, 3, 4, 5]
squared = map(lambda x: x**2, numbers)
# 返回 [1, 4, 9, 16, 25]
注意:函数参数必须接受一个输入,并返回一个输出。
filter(func, iter)
filter(function, iterable)
:根据函数的返回值筛选可迭代对象中的元素,并返回一个新的可迭代对象。
numbers = [1, 2, 3, 4, 5]
evens = filter(lambda x: x % 2 == 0, numbers)
# 返回 [2, 4]
注意:函数参数必须返回一个布尔值
reduce(func, iter)
reduce(function, iterable[, initializer])
:对可迭代对象中的元素依次应用函数,进行累积操作,并返回最终结果。
from functools import reduce
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x + y, numbers)
# 返回 15
注意:函数参数必须接受两个输入,并返回一个输出。
sorted(iter)
sorted(iterable[, key][, reverse])
: 对可迭代对象进行排序,并返回一个新的列表。
numbers = [5, 2, 1, 3, 4]
sorted_numbers = sorted(numbers)
# 返回 [1, 2, 3, 4, 5]
注意:key参数可以指定一个函数,用于排序时的自定义比较规则。
functools.partial
functools.partial(func, *args, **kwargs)
: 返回一个新的函数对象,固定部分函数参数的值,方便进行函数的重用和扩展。
from functools import partial
def multiply(x, y):
return x * y
double = partial(multiply, 2)
result = double(5)
# 返回 10
注意:partial函数可以固定部分函数参数的值,生成一个新的函数对象。