【问题标题】:How to pass function reference without using mutable type like list or dict如何在不使用 list 或 dict 等可变类型的情况下传递函数引用
【发布时间】:2021-05-10 22:39:27
【问题描述】:

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

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

这个问题是核心问题:Python functions call by reference

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

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


示例代码

**更新**:我对公开foo._on_call 不感兴趣。我试图通过引用从外部更改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

已知(不受欢迎的)解决方法:

  • 在列表中传递do_something
  • 重新创建foo 对象
  • 公开Foo_on_call 属性或使用property 装饰器

Python 版本:3.8

【问题讨论】:

  • 更直接的方式:foo._on_call = do_something_else
  • 你能提供更多的背景信息吗?这似乎是一个XY problem

标签: python function pass-by-reference immutability


【解决方案1】:

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

实现您想要的最简单和最惯用的方法是将_on_call 设为Foo 实例的公共属性,或者添加一个更新它的方法:

1。属性

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

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

(您不必重命名属性就可以做到这一点,但是将以下划线开头的属性视为不应该从类外部访问它们是一种很好的风格。)

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)

【讨论】:

  • FWIW,另一种选择是使用 setter 将其设为 property。这就像一个属性,但具有更大的灵活性。
  • 感谢@mkrieger1 提出解决方法。但是,我想弄清楚是否可以在不使用listdict 的情况下通过引用传递函数,而不是通过更改Foo 的暴露接口来解决它
  • 不,你不能那样做。
  • 好吧,你可以偷偷地分配foo._on_call = do_something_else,因为_on_call不被认为是公共接口的一部分,但那会是不好的风格。
【解决方案2】:

函数实际上是可变的,通过__code__Here's another example。但是,不知道这是否是个好主意。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 2020-09-10
    • 1970-01-01
    相关资源
    最近更新 更多