Python参数绑定器

wwodge7n  于 2022-10-22  发布在  Python
关注(0)|答案(7)|浏览(186)

如何将参数绑定到Python函数,以便以后可以在没有参数的情况下调用它(或使用较少的附加参数)?
例如:

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

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

我这里需要什么?
在框架和库中经常会发生这样的情况:当人们试图给回调函数提供参数时,会意外地立即调用函数:例如on_event(action(foo))。解决方案是使用此处描述的技术之一将foo作为参数绑定到action上。参见例如How to pass arguments to a Button command in Tkinter?Using a dictionary as a switch statement in Python
然而,有些API允许您单独传递待绑定参数,并将为您进行绑定。值得注意的是,标准库中的线程API是这样工作的。参见thread starts running before calling Thread.start
显式绑定参数也是避免使用闭包时后期绑定导致的问题的一种方法。这就是问题所在,例如,for循环或列表理解中的lambda会产生计算相同结果的单独函数。参见What do lambda function closures capture?Creating functions (or lambdas) in a loop (or comprehension)

x33g5p2x

x33g5p2x1#

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

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)
lymgl2op

lymgl2op2#

使用functools.partial

>>> 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
dzhpxtsq

dzhpxtsq3#

如果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
vjrehmav

vjrehmav4#

lambda s允许您使用较少的参数创建一个新的未命名函数并调用该函数:

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

您也可以使用functools.partial。如果您计划在函数调用中使用命名参数绑定,这也适用:

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

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

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

j2qf4p5b5#

这也会起作用:

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
mhd8tkvw

mhd8tkvw6#

在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()
j2cgzkjk

j2cgzkjk7#

这个问题通常是关于绑定参数的,但所有的答案都是关于函数的。如果您想知道,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

相关问题