Python: 将带有参数的函数传递给另一个函数

3

我有两个函数:

  1. 库函数,我无法更改,称为lib_func(func, param1)
    lib_func接受一个函数func和另一个参数param1作为参数。

  2. 用户自定义函数user_func

例如:

x = 0
y = 0
def user_func():
    global x
    global y 
    return sqrt(x*y)

现在的问题是我想将 x 作为参数传递给 user_func,而不是作为全局变量传递给 lib_func,同时将 user_func 传递给 lib_func

你也不能修改 user_func(),对吧? - Mikhail Gerasimov
是的,您可以修改user_func。 - Harit Vishwakarma
如果您可以修改user_func,那么问题在哪里?只需停止使用全局变量! - Hannes Ovrén
@Hannes 我猜你没有理解这个问题。 - Harit Vishwakarma
显然不是这样。但是如果您可以访问函数源代码,为什么那些全局变量存在以及为什么它们不能被删除,您还没有解释清楚。 - Hannes Ovrén
4个回答

3

一个函数是一个可以被调用的对象,因此定义一个带有 __call__ 方法的类,在原则上等同于定义一个函数。 至少在你所给出的上下文中是这样。

因此:

def user_func(x, y, z):
    return anything_with(x, y, z)

等价于:

class user_class(object):
    @staticmethod # staticmethod so that it can be called on the class
    def __call__(x, y, z):
        return anything_with(x, y, z)

目前这只是混淆代码,但当你创建一个具有预定义属性的实例,并且只将变量参数指定为call的参数时,魔法就会发生:

class user_class(object):
    def __init__(self, x):
        self.x = x

    def __call__(self, y, z): # No x as parameter!
        return do_anything_with(self.x, y, z) # use the predefined x here

但是,您需要改变调用lib_func的方式:
x = 0
user_class_instance = user_class(0)
result = lib_func(user_class_instance, param1)

这样它将会重复调用实例,并使用不同的 yz,但是 x 将保持不变。


大多数这种 lib_func 函数允许传递可变参数(这些参数将被传递给 user_func),例如scipy.optimize.curve_fit

curve_fit(user_func, x, y, [initial_guess_param1, param2, ...])

在这里,curve_fit内部将会调用user_func(您无需做任何事情!),示例如下:

user_func(x, initial_guess_param1, param2, ...)
# Then curve-fit modifies initial_guess_param1, param2, ... and calls it again
user_func(x, initial_guess_param1, param2, ...)
# and again modifies these and calls again
user_func(x, initial_guess_param1, param2, ...)
# ... until it finds a solution

在调用curve_fit时,xy被定义并且不会改变,但是在寻找最佳的curve_fit时,initial_guess_param1将会被更改。


1
你可以用另一个函数包装你的user_func()
def parameterized_func(local_x):
    global x
    x = local_x
    return user_func()

然后将新的parameterized_func()函数传递给lib_func()。这样做并不好,显然会改变全局变量x。我建议看看是否可以改变user_func()函数。

但我们仍然无法摆脱全局变量。 - Harit Vishwakarma
除非您有更改user_func()的权限/可能性,否则您无法真正摆脱使用全局变量。 - Hannes Ovrén

1
如果我正确理解了任务,你需要两件事情:
  1. 创建一个新函数来包装带有 x, y 参数的 user_func

  2. 使用 functools.partial 来获取传递参数的另一个函数

这是一个例子。
模块 user_module.py 中定义了 user_func
x = 0
y = 0
def user_func():
   global x
   global y 
   print('user_func', x, y)

需要完成工作的模块为 main.py:

def lib_func(func, param1):
    print('lib_func', param1)
    func()


# Create user_func with params:
import user_module

def new_user_func(x, y):
    user_module.x = x
    user_module.y = y
    user_module.user_func()


# Use functools.partial to create user_func with ready params:
from functools import partial

f = partial(new_user_func, 1, 2)
lib_func(f, 'param1')

f = partial(new_user_func, 3, 4)
lib_func(f, 'param1')

这个例子的输出:

lib_func param1
user_func 1 2

lib_func param1
user_func 3 4

lib_func 将会重复调用 user_func 并传入新的参数。 - Harit Vishwakarma
@iota,只需为每组参数创建一个带有partial的新函数即可。我更新了答案以展示它。 - Mikhail Gerasimov

-2
尝试包装user_func并返回一个新的函数给lib_func:
def wrapuserfunc(x):
    user_func.x = x
    return user_func

def user_func():
    if hasattr(user_func, 'x'):
        print user_func.x

lib_func(wrapuserfunc(1), param1)  # user_func.x = 1
# get x in user_func
print user_func.x  # x = 1

wrapuserfunc(x)运行良好。 在Python中,函数是对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接