需要两个关键字参数中的一个

Die*_*anz 4 python

我有一个可以接受关键字参数的函数,我想要其中一个.让我们说美元和欧元,我只想要其中一个.现在,我这样做(例证),但我觉得它很复杂.还有其他更好的方法吗?

def set_value(country, **kargs):

    if len(kargs) == 1:
        if kargs.keys()[0] == 'dollar':
            pass # do something
        elif kargs.keys()[0] == 'euro':
            pass # do something
        else:
            raise ValueError('One keyword argument is required: dollar=x or euro=x')
    else:
        raise ValueError('One keyword argument is required: dollar=x or euro=x')
Run Code Online (Sandbox Code Playgroud)

谢谢!

Mar*_*ers 9

您可以在字典键视图上使用set操作:

if len(kargs.viewkeys() & {'dollar', 'euro'}) != 1:
    raise ValueError('One keyword argument is required: dollar=x or euro=x')
Run Code Online (Sandbox Code Playgroud)

在Python 3中,请kargs.keys()改用.

演示设定操作的不同结果:

>>> kargs = {'dollar': 1, 'euro': 3, 'foo': 'bar'}
>>> kargs.viewkeys() & {'dollar', 'euro'}
set(['dollar', 'euro'])
>>> del kargs['euro']
>>> kargs.viewkeys() & {'dollar', 'euro'}
set(['dollar'])
>>> del kargs['dollar']
>>> kargs.viewkeys() & {'dollar', 'euro'}
set([])
Run Code Online (Sandbox Code Playgroud)

换句话说,&集合交集为您提供两组中存在的所有键的集合; 在字典和显式集合文字中.仅当存在一个且仅存在一个命名键时,交叉点的长度将为1.

如果你不希望允许任何其他关键字参数除了dollareuro,那么你也可以使用适当的子集的测试.<如果左侧集合严格小于右侧集合,则使用两个集合仅为True; 它只有比另一组更少的键,没有额外的键:

if {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}:
    raise ValueError('One keyword argument is required: dollar=x or euro=x')
Run Code Online (Sandbox Code Playgroud)

在Python 3上,可以拼写为:

if set() < kargs.keys() < {'dollar', 'euro'}:
Run Code Online (Sandbox Code Playgroud)

代替.

演示:

>>> kargs = {'dollar': 1, 'euro': 3, 'foo': 'bar'}
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
False
>>> del kargs['foo']
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
False
>>> del kargs['dollar']
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
True
>>> del kargs['euro']
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
False
Run Code Online (Sandbox Code Playgroud)

请注意,现在'foo'密钥已不再可接受.

  • `set()<kwargs.viewkeys()<{'dollar','euro'}`检查`kwargs.viewkeys()`是否是一个正确的非空子集,即`{'euro'}`或`{ '美元'}`. (2认同)
  • 这不会检测调用站点的错误,如`set_value(dolar = 5,euro = 6)`.Python通常会检测到这些错误并引发一个`TypeException`. (2认同)

Die*_*Epp 5

我们不要使用kargs.keys()[0],因为这取决于键的顺序,而这是未指定的。它现在可以工作,但它很脆弱,因为如果您添加另一个关键字参数或迁移到 Python 3,它就会崩溃。

请注意,如果None是有效值,则必须使用不同的哨兵。

def set_value(country, dollar=None, euro=None):
    if dollar is None and euro is None:
        raise TypeError('Need dollar or euro argument')
    if dollar is not None and euro is not None:
        raise TypeError('Cannot have both dollar and euro argument')
Run Code Online (Sandbox Code Playgroud)

一般来说,我会尽量避免使用,**kwargs除非我将关键字参数传递给另一个函数。如果您使用**kwargs,那么您可以拨打电话set_value(dolar=5)而永远不会注意到您拼错了“dollar”。

另请注意,引发的正确异常是TypeError

但是,如果您预计货币范围会扩大,

CURRENCIES = {'euro', 'dollar', 'quatloo', 'zorkmid'}
def set_value(country, **kwargs):
    if len(kwargs) != 1 or not CURRENCIES.issuperset(kwargs.keys()):
        raise TypeError('exactly one supported currency must be specified')
Run Code Online (Sandbox Code Playgroud)

但是,我可能不会使用单独的关键字参数:

Value = collections.namedtuple('Value', 'currency amount')
def set_value(country, value):
    ...

set_value(country, Value('USD', Decimal('15.30'))
Run Code Online (Sandbox Code Playgroud)

  • 因为 len(kargs) == 1,所以顺序并不重要,因为只有一个键存在。 (3认同)
  • 添加另一个关键字参数时会发生什么?迁移到 Python 3 后会发生什么? (2认同)
  • 当然,这个问题的“正确”答案完全是主观的,但我更喜欢这种方法。如果您知道所有可能的参数(并且只有其中两个),为什么您不想将它们列在函数参数列表中呢?执行任何其他操作都会使用户更难阅读该函数以确定其实际工作原理。我真的不想阅读函数的整个源代码来确定它接受哪些参数。 (2认同)