如何将参数绑定到Python中的函数?

yc0p9oo0  于 2023-04-10  发布在  Python
关注(0)|答案(7)|浏览(158)

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

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

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

这里需要的magic_function是什么?
在框架和库中,当人们试图给回调函数给予参数时,经常会意外地立即调用函数:例如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。如果您试图设置自己的API,请参阅How can I write a simple callback function?
显式绑定参数也是一种避免使用闭包时后期绑定引起的问题的方法。例如,for循环或列表解析中的lambda会产生计算相同结果的单独函数。参见What do lambda function closures capture?Creating functions (or lambdas) in a loop (or comprehension)

m0rkklqb

m0rkklqb1#

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

eagi6jfj2#

使用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
6qqygrtg

6qqygrtg3#

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

aurhwmvo4#

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
f87krz0w

f87krz0w5#

这也会起作用:

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
af7jpaap

af7jpaap6#

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

rekjcdws7#

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

相关问题