使用类型提示区分 Python 中的纯函数和不纯函数
Distinguish Pure and Impure functions in Python using Type Hints
有没有办法使用类型提示来显式表示纯函数(即没有副作用的函数)?
考虑以下示例,相同的功能,一个没有副作用,另一个有。
def add_two_pure(numbers: list[float]) -> list[float]:
return [x + 2 for x in numbers]
numbers = [1.5, 2]
add_two_pure(numbers)
assert numbers == [1.5, 2]
# This is a bad practice, but it is just for illustration
def add_two_impure(numbers: list[float]) -> list[float]:
for index, value in enumerate(numbers):
numbers[index] = value + 2
return numbers
numbers = [1.5, 2]
add_two_impure(numbers)
assert numbers == [3.5, 4]
我的第一个猜测是使用类似 Final
的东西,但 Pylance 抱怨“在此上下文中不允许使用“Final””:
from typing import Final
# Invalid Context
def add_two_pure(numbers: Final[list[float]]) -> list[float]:
...
有什么方法可以使这种区分更加明确吗?或者是否有任何 PEP 已经在讨论这个?
这是一个概念性问题,不需要特定的 Python 版本。
看起来没有,反正 MyPy 也没有。看到这个问题:https://github.com/python/mypy/issues/4468
Python还真没有纯函数的概念
您只能传递不可变对象以确保它们不会被更改。例如冻结集、元组或原始值。
或者,您可以编写自己的装饰器来断言它们不会更改您的变量。例如
def purity_check(func):
def assert_purity(*args, **kwargs):
hash_or_else = lambda x: hash(x) if isinstance(x, Hashable) else hash(str(x))
original_ids = list(map(hash_or_else, [*args, *kwargs.values()]))
func(*args, **kwargs)
assert all(
[
a == b
for a, b in zip(
list(map(hash_or_else, [*args, *kwargs.values()])), original_ids
)
]
), f"{func.__name__} is not pure"
return assert_purity
正如@Charles Duffy 提到的,您永远无法知道它是否有其他副作用,例如 global
关键字、网络请求、os-level 更改等。您必须使用静态分析那。
有没有办法使用类型提示来显式表示纯函数(即没有副作用的函数)?
考虑以下示例,相同的功能,一个没有副作用,另一个有。
def add_two_pure(numbers: list[float]) -> list[float]:
return [x + 2 for x in numbers]
numbers = [1.5, 2]
add_two_pure(numbers)
assert numbers == [1.5, 2]
# This is a bad practice, but it is just for illustration
def add_two_impure(numbers: list[float]) -> list[float]:
for index, value in enumerate(numbers):
numbers[index] = value + 2
return numbers
numbers = [1.5, 2]
add_two_impure(numbers)
assert numbers == [3.5, 4]
我的第一个猜测是使用类似 Final
的东西,但 Pylance 抱怨“在此上下文中不允许使用“Final””:
from typing import Final
# Invalid Context
def add_two_pure(numbers: Final[list[float]]) -> list[float]:
...
有什么方法可以使这种区分更加明确吗?或者是否有任何 PEP 已经在讨论这个?
这是一个概念性问题,不需要特定的 Python 版本。
看起来没有,反正 MyPy 也没有。看到这个问题:https://github.com/python/mypy/issues/4468
Python还真没有纯函数的概念
您只能传递不可变对象以确保它们不会被更改。例如冻结集、元组或原始值。
或者,您可以编写自己的装饰器来断言它们不会更改您的变量。例如
def purity_check(func):
def assert_purity(*args, **kwargs):
hash_or_else = lambda x: hash(x) if isinstance(x, Hashable) else hash(str(x))
original_ids = list(map(hash_or_else, [*args, *kwargs.values()]))
func(*args, **kwargs)
assert all(
[
a == b
for a, b in zip(
list(map(hash_or_else, [*args, *kwargs.values()])), original_ids
)
]
), f"{func.__name__} is not pure"
return assert_purity
正如@Charles Duffy 提到的,您永远无法知道它是否有其他副作用,例如 global
关键字、网络请求、os-level 更改等。您必须使用静态分析那。