使用类型提示区分python中的纯和不纯粹的功能

发布于 2025-01-24 07:19:48 字数 917 浏览 0 评论 0原文

有没有一种方法可以使用类型提示明确表示纯函数(即没有副作用的功能)?

考虑以下示例,相同的funcitonation,一种没有副作用,另一个则没有。

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抱怨“在此上下文中不允许”:

from typing import Final

# Invalid Context
def add_two_pure(numbers: Final[list[float]]) -> list[float]:
    ...

有什么方法可以使这种区别更加明确?还是已经讨论了这一点?

这是一个概念上的问题,不需要特定的python版本。

Is there a way to use type hints to represent pure functions explicitly (i.e. functions that have no side effects)?

Consider the following example, same funcitonality, one without side effects and the other with.

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]

My first guess was to use something like Final this but Pylance complains with ""Final" not allowed in this context":

from typing import Final

# Invalid Context
def add_two_pure(numbers: Final[list[float]]) -> list[float]:
    ...

Is there any way to make this distinction more explicit? Or is there any PEP already discussing this?

This is a conceptual question, no particular Python version is required.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谜兔 2025-01-31 07:19:48

看起来不,无论如何都不是Mypy。请参阅此问题: https://github.com/python/mypy/mypy/mypy/sissues/4468

It looks like no, not with MyPy anyway. See this issue: https://github.com/python/mypy/issues/4468

茶底世界 2025-01-31 07:19:48

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级别的更改等。您必须对此进行静态分析。

Python doesn't really have the concept of pure functions.

You can only pass immutable objects to make sure they don't get changed. Such as frozenset, tuple or primitive values.

Alternatively you could write your own decorator to assert that they don't change your variables. e.g.

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

As @Charles Duffy mentioned you can never know if it has other side effects like the global keyword, network requests, os-level changes, etc. You'd have to employ static analysis for that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文