部分:禁止覆盖给定的关键字参数

问题描述

有没有一种方法可以禁止部分覆盖给定的关键字参数?假设我要创建函数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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...