问题描述
有没有一种方法可以禁止部分覆盖给定的关键字参数?假设我要创建函数bar
,该函数始终将a
设置为1
。在以下代码中:
from functools import partial
def foo(a,b):
print(a)
print(b)
bar = partial(foo,a=1)
bar(b=3) # This is fine and prints 1,3
bar(a=3,b=3) # This prints 3,3
您可以愉快地致电bar
并将a
设置为3
。是否可以从bar
中创建foo
并确保调用bar(a=3,b=3)
会引发错误或无声地忽略a=3
并继续使用a=1
,如部分?
解决方法
您真的需要使用局部吗? 您通常可以使用较少的参数来定义新的功能栏。
赞:
def bar(a):
b = 1
foo(a,b)
这将导致错误。
或类似:
def bar(a,b=1):
b = 1 #ignored provided b
foo(a,b)
这将忽略b。
编辑:如果要单行使用lambda:
像:bar = lambda a:foo(a,b=1)
或bar = lambda a,b=1:foo(a,b=1)
这是设计。 partial
的文档说(强调我的):
functools.partial(func,/,*args,**keywords)
返回一个新的部分对象,该对象在被调用时的行为类似于使用位置参数args和关键字arguments关键字调用的func。如果将更多参数提供给调用,则将它们附加到args。 如果提供了其他关键字参数,它们将扩展并覆盖关键字。
如果您不希望这样做,可以手动拒绝冻结的关键字参数:
def freeze(f,**kwargs):
frozen = kwargs
def wrapper(*args,**kwargs):
kwargs.update(frozen)
return f(*args,**kwargs)
return wrapper
您现在可以这样做:
>>> baz = freeze(foo,a=1)
>>> baz(b=3,a=2)
1
3
,
如果要在覆盖发生时引发错误,则可以创建partial
的自定义实现:
class _partial:
def __init__(self,f,**kwargs):
self.f,self.kwargs = f,kwargs
def __call__(self,**kwargs):
if (p:=next((i for i in kwargs if i in self.kwargs),None)) is not None:
raise ValueError(f"parameter '{p}' already specified")
return self.f(**self.kwargs,**kwargs)
def foo(a,b):
print(a)
print(b)
>>> bar = _partial(foo,a=1)
>>> bar(b=3)
1
3
>>> bar(a=3,b=3)
Traceback (most recent call last):
File "<stdin>",line 1,in <module>
File "<stdin>",line 6,in __call__
ValueError: parameter 'a' already specified