【问题标题】:Python: Redefine function so that it references its own selfPython:重新定义函数,使其引用自己的自身
【发布时间】:2019-02-20 20:38:49
【问题描述】:

假设我有一些函数fun,它的实际代码体是我无法控制的。我可以创建一个新函数,在调用fun 之前进行一些预处理,即

def process(x):
    x += 1
    return fun(x)

如果我现在希望 process 代替 fun 用于将来对 fun 的所有调用,我需要执行类似的操作

# Does not work
fun = process

但这不起作用,因为这会产生循环引用问题,因为现在 fun 是从 fun 的主体中调用的。我发现的一种解决方案是在process 中引用fun 的副本,如下所示:

# Works
import copy
fun_cp = copy.copy(fun)
def process(x):
    x += 1
    return fun_cp(x)
fun = process

但是这个解决方案让我很困扰,因为我真的不知道 Python 如何构造函数的副本。我想我的问题与使用继承和super 函数扩展类方法的问题相同,但这里我没有类。

我怎样才能正确地做到这一点?我认为这是一项足够普遍的任务,应该存在一些或多或少惯用的解决方案,但我没有找到它。

【问题讨论】:

    标签: python python-3.x function reference functional-programming


    【解决方案1】:

    Python 不是构造函数的副本。 copy.copy(fun) 只返回fun;不同之处在于您将其保存到 fun_cp 变量中,该变量与您保存 process 的变量不同,因此当 process 尝试查找它时,它仍在 fun_cp 中。

    我会做类似于你所做的事情,将原始函数保存到不同的变量中,只是没有“副本”:

    original_fun = fun
    def fun(x):
        x += 1
        return original_fun(x)
    

    如果您想对多个函数应用相同的包装,定义一个装饰器并执行fun = decorate(fun) 更可重用,但对于一次性的,它的工作量比必要的要多,而且需要额外的缩进。

    【讨论】:

      【解决方案2】:

      这看起来像是 python 闭包的一个用例。让一个函数返回你的函数。

      def getprocess(f):
          def process(x):
              x += 1
              return f(x)  # f is referenced from the enclosing scope.
      
          return process
      
      myprocess = getprocess(fun) 
      myprocess = getprocess(myprocess) 
      

      【讨论】:

      • 我不明白你为什么给getprocess打了两次电话?当然,这不会导致名为fun 的变量在调用时使用给定参数加1 调用原始fun。如果我用fun = getprocess(fun) 替换最后两行,我想我会得到我想要的。 :-)
      • @jmd_dk 答案是基于我对您在问题中给出的有点模糊的描述的理解。我不确定我的最后两行是否充分满足了您的需求,但我确实认为闭包是要走的路。
      【解决方案3】:

      感谢coldspeed 使用闭包的想法。一个完全有效和完善的解决方案是

      import functools
      
      def getprocess(f):
          @functools.wraps(f)
          def process(x):
              x += 1
              return f(x)
          return process
      
      fun = getprocess(fun)
      

      请注意,这 100% 等同于将装饰器 (getprocess) 应用于 fun。我想不出这个解决方案,因为专用装饰器语法@getprocess 只能在函数的定义位置使用(这里是fun)。不过,要将其应用于现有函数,只需执行fun = getprocess(fun)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-14
        • 1970-01-01
        • 1970-01-01
        • 2019-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多