Skip to main content

函数

info

API的行为在任何两个连续版本之间不得以不兼容的方式更改,除非它正在经历弃用过程。不能在任何两个连续版本之间在没有通知的情况下删除功能。

PEP 387 – 向后兼容性政策

函数

为了减少重复,自定义函数登场。

def

使用 def 关键字定义函数。参数为输入,return 返回输出。

def add(a, b):
"""
add two nums
:param a: first num
:param b: second num
:return: None
"""
print(a + b)

调用函数时传入具体参数值。

# Python并没有限定参数的类型,因此可以使用不同的参数类型:
print(add(2, 3))

print(add('foo', 'bar')) # foobar

参数传递方式:位置参数和关键字参数。

add(a=2, b=3)

add(b='morning', a='good')

add(2, b=3) # 5

return

return 语句返回值并终止函数执行。无 return 时返回 None。

def add(a, b):
return a + b

def add_none(a, b):
a + b


print(add(2, 3)) # 5
print(add_none(2, 3)) # None

yield

info

生成器让Python能够以内存高效的方式处理大量数据。它们实现了惰性求值,只在需要时计算值,体现了Python对性能和内存使用的关注。

def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b

PEP 255 – 简单生成器

yield 暂停函数执行并返回值。使用 yield 的函数称为生成器函数,返回生成器对象。适用于逐个产生大量数据的场景。

def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b

yield from 委派子生成器,建立双向通道。

def g1(x):
yield range(x, 0, -1)
yield range(x)
print(list(g1(5)))
#[range(5, 0, -1), range(0, 5)]

def g2(x):
yield from range(x, 0, -1)
yield from range(x)
print(list(g2(5)))
#[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
tip

生成器表达式:使用圆括号创建生成器对象,内存效率更高。

(expression for item in iterable)

示例:

# 创建生成器
squares_gen = (x**2 for x in range(10))
print(type(squares_gen)) # <class 'generator'>

# 迭代生成器
for square in squares_gen:
print(square, end=' ') # 0 1 4 9 16 25 36 49 64 81

lambda

lambda 创建匿名函数,语法简洁。

def add(a, b):
return a + b
# 等价于
add = lambda a, b: a + b

print(add(2, 3)) # 5

函数的参数类型

位置参数与默认参数

位置参数:按顺序传递,必须提供。

默认参数:有默认值,调用时可省略。

def quad(x, a=1, b=0, c=0):
"""
二次函数计算器
:param x: 自变量
:param a: 二次项系数,默认为1
:param b: 一次项系数,默认为0
:param c: 常数项,默认为0
:return: 计算结果
"""
return a * x * x + b * x + c

调用示例:

# 只提供位置参数x,其他使用默认值
quad(2.0) # 结果: 4.0 (1*2*2 + 0*2 + 0)

# 提供位置参数x和关键字参数b
quad(2.0, b=3) # 结果: 10.0 (1*2*2 + 3*2 + 0)

# 提供位置参数x和a,其他使用默认值
quad(2.0, 2) # 结果: 8.0 (2*2*2 + 0*2 + 0)

# 使用关键字参数,顺序可以改变
quad(2.0, c=5, a=2) # 结果: 13.0 (2*2*2 + 0*2 + 5)
默认参数的重要陷阱

默认参数只计算一次! 当默认值是可变对象(如列表、字典)时,所有函数调用会共享同一个对象,这通常不是我们想要的行为。

# ❌ 错误示例:默认参数使用可变对象
def add_item(item, my_list=[]):
my_list.append(item)
return my_list

print(add_item('a')) # ['a']
print(add_item('b')) # ['a', 'b'] - 意外结果!

# ✅ 正确做法:使用None作为默认值
def add_item(item, my_list=None):
if my_list is None:
my_list = []
my_list.append(item)
return my_list

print(add_item('a')) # ['a']
print(add_item('b')) # ['b'] - 正确结果!

原因:Python在定义函数时计算默认参数值,而不是在每次调用时计算。对于不可变对象(如数字、字符串),这不是问题;但对于可变对象,所有调用会共享同一个对象。

不定长参数

位置不定长参数:*args

表示参数数目不定,可以看成一个元组

使用如下方法,可以使函数接受不定数目的参数,把第一个参数后面的参数当作元组中的元素。

def add(x, *args):
total = x
for arg in args:
total += arg
return total

print(add(1, 2, 3, 4, 5)) # 15
print(add(1, 2)) # 3

关键字不定长参数:**kwargs

表示参数数目不定,可以看成一个字典

def add(x, **kwargs):
total = x
for arg, val in kwargs.items():
print("adding ", arg)
total += val
return total

add(1, a=2, b=3) # 6

混合使用 *args**kwargs

# 可以接收任意数目的位置参数和键值对参数:
def fun1(*args, **kwargs):
print(args, kwargs)

fun1(2, 3, a="bar", b=10) # (2, 3) {'a': u'bar', 'b': 10}

函数参数分隔符

/ - 位置专用参数分隔符

作用:/ 之前的参数只能通过位置传递,不能使用关键字。

* - 关键字专用参数分隔符

作用:* 之后的参数只能通过关键字传递,不能使用位置

def func1(a, b, /):
"""a和b只能通过位置传递,防止将来参数名变更破坏兼容性。"""
return a + b

# 正确调用
print(func1(1, 2)) # ✅ 3

# 错误调用
# print(func1(a=1, b=2)) # ❌ TypeError: 只能位置传递

def func2(*, x, y):
"""x和y只能通过关键字传递,强制描述可以提高代码可读性和维护性。"""
return x * y

# 正确调用
print(func2(x=3, y=4)) # ✅ 12

# 错误调用
# print(func2(3, 4)) # ❌ TypeError: 只能关键字传递

def func3(pos_only, /, *, kwd_only):
"""
pos_only: 只能位置传递
kwd_only: 只能关键字传递
"""
return f"{pos_only}-{kwd_only}"

print(func3(1, kwd_only=3)) # ✅ "1-3"
# 其他调用都为错误调用

类型注解

类型注解是可选的,用于描述函数参数和返回值的类型。如果需要更加复杂的类型注解,可以使用 typing 模块。

# 声名 T 可以是 int 或 str
def add[T: (int, str)](a: T, b: T) -> T:
return a + b

print(add(1, 2)) # 3
print(add('foo', 'bar')) # foobar

递归

在函数中调用自身,称为递归。递归是一种解决问题的方法,它把一个问题分解为更小的子问题,直到子问题可以被直接解决。

def fact(n):
if n == 1:
return 1
return n * fact(n - 1)

print(fact(5)) # 120

内置函数

map 函数

map() 对序列每个元素应用函数,返回映射结果。

map函数签名:map(function, iterable, ...) -> map object

参数说明:

  • function:要对每个元素执行的函数
  • iterable:要映射的可迭代对象
  • ...:可以传入多个可迭代对象

返回值:

  • 返回一个map对象(迭代器)
def sqr(x):
return x ** 2

a = [2, 3, 4]
result = map(sqr, a)
print(type(result)) # <class 'map'>

# map返回的是个迭代器对象, 可以转化为list显示
print(list(result)) # [4,9,16]

map() 支持多序列,对应元素作为函数参数:

def add(a, b):
return a + b

a = (2, 3, 4)
b = [10, 11, 15]
list(map(add, a, b)) # [12, 14, 19]

reduce 函数

reduce() 对序列元素进行累积运算。

reduce函数签名:reduce(function, iterable[, initializer]) -> value

参数说明:

  • function:累积函数,接受两个参数
  • iterable:要累积的可迭代对象
  • initializer:可选的初始值

返回值:

  • 返回累积的结果
from functools import reduce

def add(x, y) : # 两数相加
return x + y
sum1 = reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
sum2 = reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
print(sum1)
print(sum2)

推荐库

  • functools: 提供高阶函数和装饰器
  • itertools: 提供迭代器工具
  • operator: 提供操作符函数
  • typing: 提供类型提示