如何在 Python 中将参数绑定到函数?
- 2024-11-28 08:37:00
- admin 原创
- 6
问题描述:
如何将参数绑定到 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
参数绑定到。例如,请参阅如何在 Tkinter 中将参数传递给按钮命令?和在 Python 中使用字典作为 switch 语句。action
但是,有些 API 允许您单独传递要绑定的参数,并会为您完成绑定。值得注意的是,标准库中的线程 API 就是这样工作的。请参阅在调用 Thread.start 之前线程开始运行。如果您尝试像这样设置自己的 API,请参阅如何编写一个简单的回调函数?。
显式绑定参数也是避免使用闭包时后期绑定导致的问题的一种方法。例如,当循环或列表推导式lambda
内部for
产生计算相同结果的单独函数时,就会出现此问题。请参阅lambda 函数闭包捕获了什么?和在循环(或推导式)中创建函数(或 lambda)。
解决方案 1:
functools.partial
返回一个可调用函数,其中包装了部分或全部参数并被冻结。
import sys
import functools
print_hello = functools.partial(sys.stdout.write, "Hello world
")
print_hello()
Hello world
上述用法与以下用法等效lambda
。
print_hello = lambda *a, **kw: sys.stdout.write("Hello world
", *a, **kw)
解决方案 2:
使用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
解决方案 3:
如果functools.partial
没有的话就可以轻松模拟:
>>> make_printer = lambda s: lambda: sys.stdout.write("%s
" % 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:
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
解决方案 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
解决方案 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
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件