Python: Redefine function so that it references its own self

与世无争的帅哥 提交于 2021-01-28 09:47:38

问题


Say I have got some function fun, the actual code body of which is out of my control. I can create a new function which does some preprocessing before calling fun, i.e.

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

If I now want process to take the place of fun for all future calls to fun, I need to do something like

# Does not work
fun = process

This does not work however, as this creates a cyclic reference problem as now fun is called from within the body of fun. One solution I have found is to reference a copy of fun inside of process, like so:

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

but this solution bothers me as I don't really know how Python constructs a copy of a function. I guess my problem is identical to that of extending a class method using inheritance and the super function, but here I have no class.

How can I do this properly? I would think that this is a common enough task that some more or less idiomatic solution should exist, but I have had no luck finding it.


回答1:


Python is not constructing a copy of your function. copy.copy(fun) just returns fun; the difference is that you saved that to the fun_cp variable, a different variable from the one you saved process to, so it's still in fun_cp when process tries to look for it.

I'd do something similar to what you did, saving the original function to a different variable, just without the "copy":

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

If you want to apply the same wrapping to multiple functions, defining a decorator and doing fun = decorate(fun) is more reusable, but for a one-off, it's more work than necessary and an extra level of indentation.




回答2:


This looks like a use case for python's closures. Have a function return your function.

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) 



回答3:


Credit to coldspeed for the idea of using a closure. A fully working and polished solution is

import functools

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

fun = getprocess(fun)

Note that this is 100% equivalent to applying a decorator (getprocess) to fun. I couldn't come up with this solution as the dedicated decorator syntax @getprocess can only be used at the definition place of the function (here fun). To apply it on an existing function though, just do fun = getprocess(fun).



来源:https://stackoverflow.com/questions/52358965/python-redefine-function-so-that-it-references-its-own-self

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!