函数
API的行为在任何两个连续版本之间不得以不兼容的方式更改,除非它正在经历弃用过程。不能在任何两个连续版本之间在没有通知的情况下删除功能。
函数
为了减少重复,自定义函数登场。
def
在 Python 中可以使用 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
传入参数时,Python 提供了两种选项,
第一种是上面使用的按照位置传入参数,
另一种则是使用关键词模式,显式地指定参数的值:
add(a=2, b=3)
add(b='morning', a='good')
add(2, b=3) # 5
return
return 语句用于从函数中返回值。如果函数没有 return 语句,则返回 None。
当执行到 return,后续的逻辑代码不再执行,直接返回。
def add(a, b):
return a + b
print(add(2, 3)) # 5
yield
生成器让Python能够以内存高效的方式处理大量数据。它们实现了惰性求值,只在需要时计算值,体现了Python对性能和内存使用的关注。
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
yield 是暂停的意思(它有程序中起着类似红绿灯中等红灯的作用)
使用了 yield 的函数被称为生成器函数(generator function),调用生成器函数会返回一个生成器(generator)对象。
如果要返回的数据是通过 for 等循环生成的迭代器类型数据(如列表、元组),yeild 则可以在循环内部逐个元素返回。
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
yiled 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]
创建生成器对象的另一个方式是使用生成器表达式。
生成器表达式与列表推导式类似,但使用圆括号,返回生成器对象而不是列表,具有内存效率优势。
基本语法:
(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):
return a * x * x + b * x + c
quad(2.0)
quad(2.0, b=3)
不定长参数
位置不定长参数:*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
混合使用
# 可以接收任意数目的位置参数和键值对参数:
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
内置函数
map 函数
map 函数
map() 会根据提供的函数对指定序列做映射。
map(aFun, aSeq)
def sqr(x):
return x ** 2
a = [2, 3, 4]
result = map(sqr, a) # [4,9,16]
type(result)
# map返回的是个迭代器对象, 可以转化为list显示
list(result)
事实上,根据函数参数的多少,map 可以接受多组序列, 将其对应的元素作为参数传入函数:
def add(a, b):
return a + b
a = [2, 3, 4]
list(map(sqr, a)) # [4,9,16]
a = (2, 3, 4)
b = [10, 11, 15]
list(map(add, a, b)) # [12, 14, 19]
reduce 函数
reduce() 函数会对参数序列中元素进行累积。
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)
递归
一般对于分治法,要用递归,不过在 python 中不怎么用,更高效的处理非波切利算法:
def fib(n):
"""Fib without recursion."""
a, b = 0, 1
for i in range(1, n + 1):
a, b = b, a + b
return b
print([fib(i) for i in range(10)])
内置函数
map 函数
map 函数用于将一个函数应用到序列的每个元素上,并返回一个迭代器对象。
def sqr(x):
return x ** 2
a = [2, 3, 4]
result = map(sqr, a) # [4,9,16]
type(result)
推荐库
- functools: 提供高阶函数和装饰器
- itertools: 提供迭代器工具
- operator: 提供操作符函数
- typing: 提供类型提示