【问题标题】:Python Argument BindersPython 参数绑定器
【发布时间】:2008-11-10 14:01:22
【问题描述】:

如何将参数绑定到 Python 方法以存储空函子以供以后调用?类似于 C++ 的boost::bind

例如:

def add(x, y):
    return x + y

add_5 = magic_function(add, 5)
assert add_5(3) == 8

【问题讨论】:

  • 我终于找到了这个问题的一个版本,其中接受和流行的答案都是关于 functools.partial 而不是一些嵌套的 lambda hack 或默认参数绑定滥用。已收藏。

标签: python partial-application


【解决方案1】:

functools.partial 返回一个可调用的包装函数,其中部分或全部参数被冻结。

import sys
import functools

print_hello = functools.partial(sys.stdout.write, "Hello world\n")

print_hello()
Hello world

上面的用法等价于下面的lambda

print_hello = lambda *a, **kw: sys.stdout.write("Hello world\n", *a, **kw)

【讨论】:

  • 对于 python2.6 至少你可以使用 from future import print_function
【解决方案2】:

我对 boost::bind 并不太熟悉,但是来自 functoolspartial 函数可能是一个好的开始:

>>> from functools import partial

>>> def f(a, b):
...     return a+b

>>> p = partial(f, 1, 2)
>>> p()
3

>>> p2 = partial(f, 1)
>>> p2(7)
8

【讨论】:

  • 这是一个比接受的答案更好的例子,因为它显示了部分绑定。
  • ...虽然如果函数f 本身没有对称处理它的两个参数会更好,这样两个参数中的哪一个被绑定在部分绑定中(我假设是第一个) - 如def f(a, b): return a + 2*b
【解决方案3】:

如果functools.partial 不可用,则可以轻松模拟:

>>> make_printer = lambda s: lambda: sys.stdout.write("%s\n" % s)
>>> import sys
>>> print_hello = make_printer("hello")
>>> print_hello()
hello

或者

def partial(func, *args, **kwargs):
    def f(*args_rest, **kwargs_rest):
        kw = kwargs.copy()
        kw.update(kwargs_rest)
        return func(*(args + args_rest), **kw) 
    return f

def f(a, b):
    return a + b

p = partial(f, 1, 2)
print p() # -> 3

p2 = partial(f, 1)
print p2(7) # -> 8

d = dict(a=2, b=3)
p3 = partial(f, **d)
print p3(), p3(a=3), p3() # -> 5 6 5

【讨论】:

    【解决方案4】:

    lambdas 允许您使用更少的参数创建一个新的未命名函数并调用该函数!

    >>> def foobar(x,y,z):
    ...     print "%d, %d, %d" % (x,y,z)
    >>> foobar(1,2,3) # call normal function
    
    >>> bind = lambda x: foobar(x, 10, 20) # bind 10 and 20 to foobar
    >>> bind(1) # print 1, 10, 20
    
    >>> bind = lambda: foobar(1,2,3) # bind all elements  
    >>> bind()  # print 1, 2, 3
    

    编辑

    https://docs.python.org/2/library/functools.html#functools.partial

    如果您打算在函数调用中使用命名参数绑定,这也适用:

    >>> from functools import partial
    >>> barfoo = partial(foobar, x=10)
    >>> barfoo(y=5,z=6)
    21
    

    请注意,如果从左侧绑定参数,则需要按名称调用参数。如果从右侧绑定,它会按预期工作。

    >>> barfoo(5,6) 
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: foobar() got multiple values for keyword argument 'x'
    >>> f = partial(foobar, z=20)
    >>> f(1,1)
    22        
    

    【讨论】:

    • 这应该是公认的答案。这是将参数绑定到可调用对象的 Pythonic 方式
    【解决方案5】:

    这也可以:

    def curry(func, *args):
        def curried(*innerargs):
           return func(*(args+innerargs))
        curried.__name__ = "%s(%s, ...)" % (func.__name__, ", ".join(map(str, args)))
        return curried
    
    >>> w=curry(sys.stdout.write, "Hey there")
    >>> w()
    Hey there
    

    【讨论】:

    • 这不是咖喱。柯里化适用于具有多个参数的函数。咖喱是这样工作的:给定g = curry(f),我们有f(x1,x2,...) = g(x1)(x2)...
    【解决方案6】:

    可以在 Python 中以这种方式定义函子。它们是可调用的对象。 “绑定”只是设置参数值。

    class SomeFunctor( object ):
        def __init__( self, arg1, arg2=None ):
            self.arg1= arg1
            self.arg2= arg2
        def __call___( self, arg1=None, arg2=None ):
            a1= arg1 or self.arg1
            a2= arg2 or self.arg2
            # do something
            return
    

    你可以做这样的事情

    x= SomeFunctor( 3.456 )
    x( arg2=123 )
    
    y= SomeFunctor( 3.456, 123 )
    y()
    

    【讨论】:

    • 有趣的模式,不过有很多用于琐碎功能的样板。
    • 您可以根据您的实际用例将其缩减为相当简单的内容。原始问题没有提供有关绑定如何发生的指导。没有细节,有太多的基础无法涵盖。
    【解决方案7】:

    这个问题通常是关于绑定参数的,但所有答案都是关于函数的。如果您想知道,partial 也适用于类构造函数(即使用类而不是函数作为第一个参数),这对于工厂类很有用。你可以这样做:

    from functools import partial
    
    class Animal(object):
        def __init__(self, weight, num_legs):
            self.weight = weight
            self.num_legs = num_legs
            
    animal_class = partial(Animal, weight=12)
    snake = animal_class(num_legs = 0)
    print(snake.weight) # prints 12
    

    【讨论】:

      猜你喜欢
      • 2020-11-03
      • 2020-08-07
      • 2011-06-30
      • 2011-05-22
      相关资源
      最近更新 更多