如何在不使用列表或字典等可变类型的情况下传递函数引用

How to pass function reference without using mutable type like list or dict

我的目标:传递对函数的引用,并能够在以后更新函数。

在 Python 中,我相信函数是通过引用传递的,但函数的引用被认为是不可变的。因此,该功能以后无法更新。

本题进入核心问题:Python functions call by reference

答案都指向解决方法:在可变类型中传递函数,例如 listdict.

我想知道:是否有更直接的方法?可能有一些 functools 函数、types 实用程序或外部库可以实现此功能行为?


示例代码

**更新**:我没兴趣制作foo._on_callpublic。我试图通过引用从外部更改 on_call,而不是直接在 foo 对象上实际操作。

from typing import Callable, List

class Foo:
    def __init__(self, on_call: Callable[[], int]):
        self._on_call = on_call

    def __call__(self) -> int:
        return self._on_call()

def do_something() -> int:
    return 0

def do_something_else() -> int:
    return 1

foo = Foo(do_something)

do_something = do_something_else  # Updating do_something
print(do_something())  # This prints 1 now
print(foo())  # This still prints 0, I want this to print 1 now too

已知(不良)解决方法:

Python版本:3.8

Foo 之外分配 do_something = do_something_else 不会更改称为 do_something 的函数,它只是将模块范围中的名称 do_something 指向不同的功能。 Foo 实例范围内的名称 _on_call 不受此影响,仍指向原始函数。

实现你想要的最简单和最惯用的方法是使 _on_call 成为 Foo 实例的 public 属性,或者添加一个更新它的方法:

1。属性

class Foo:
    def __init__(self, on_call):
        self.on_call = on_call
    # ...

foo = Foo(do_something)
# ...
foo.on_call = do_something_else

(您不必重命名属性即可执行此操作,但将下划线开头的属性视为不应该从 class 外部访问的属性是一种很好的风格。)

2。方法

class Foo:
    def __init__(self, on_call):
        self._on_call = on_call
    def update(self, on_call):
        self._on_call = on_call
    # ...

foo = Foo(do_something)
# ...
foo.update(do_something_else)

函数实际上是可变的,通过 __code__. 。但是,不知道这是否是个好主意。

do_something.__code__ = do_something_else.__code__
print(do_something())  # -> 1
print(foo())  # -> 1