【问题标题】:Python: Passing function with arguments to a functionPython:将带有参数的函数传递给函数
【发布时间】:2016-06-29 03:13:22
【问题描述】:

我有两个功能:

  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,同时将 user_func 传递给 lib_func

【问题讨论】:

  • 你也不能修改 user_func() 对吧?
  • 是的,你可以修改 user_func
  • 如果可以修改user_func,有什么问题?停止使用全局变量!
  • @Hannes 我猜你没有得到问题。
  • 显然不是。但是您还没有解释为什么这些全局变量存在以及如果您可以访问函数源,为什么它们不能被删除。

标签: python numpy scipy scikit-learn


【解决方案1】:

函数只是一个可以调用的对象,因此使用__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, ...])

user_func 将在内部被 curve_fit 调用(您无需执行任何操作!)例如:

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

xy 已定义且在调用 curve_fit 时不会更改,但 initial_guess_param1 将在找到最佳 curve_fit 时更改 .

【讨论】:

    【解决方案2】:

    你可以用另一个函数包裹你的user_func()

    def parameterized_func(local_x):
        global x
        x = local_x
        return user_func()
    

    然后将新的parameterized_func() 函数传递给您的lib_func()。 这不是很好,显然会改变全局x 变量。 我建议调查一下,看看你是否不能改为更改 user_func() 函数。

    【讨论】:

    • 但我们仍然无法摆脱全局变量。
    • 除非您有权/可能更改user_func(),否则您无法真正摆脱使用全局变量。
    【解决方案3】:

    如果我对任务的理解正确,你需要做两件事:

    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。
    • @iota,只需为每组参数创建带有部分的新函数。我更新了答案以显示它。
    【解决方案4】:

    尝试缠绕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 中的对象。

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 2015-08-29
      • 2015-01-23
      • 1970-01-01
      • 2014-10-31
      • 2019-03-29
      • 2010-10-22
      相关资源
      最近更新 更多