我有一个可以接受关键字参数的函数,我想要其中一个。让我们说美元和欧元,我只想要其中一个。现在,我这样做(例证),但我觉得它很复杂。还有其他更好的方法吗?
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')
谢谢!
答案 0 :(得分:8)
您可以在dictionary keys view上使用设置操作:
if len(kargs.viewkeys() & {'dollar', 'euro'}) != 1:
raise ValueError('One keyword argument is required: dollar=x or euro=x')
在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([])
换句话说,&
集合交集为您提供两个集合中存在的所有键的集合;在字典和显式集合文字中。仅当存在一个且仅存在一个命名键时,交叉点的长度才为1.
如果您不希望在dollar
和euro
之外允许任何其他关键字参数,那么您也可以使用正确的子集测试。如果左侧集合严格小于右侧集合,则将<
与两个集合使用仅为True;它只有更少的键而不是其他组,而且没有额外的键:
if {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}:
raise ValueError('One keyword argument is required: dollar=x or euro=x')
在Python 3上,可拼写为:
if set() < kargs.keys() < {'dollar', 'euro'}:
代替。
演示:
>>> 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
请注意,现在'foo'
密钥已不再可接受。
答案 1 :(得分:2)
我们不要使用kargs.keys()[0]
,因为这取决于键的顺序,这是未指定的。它现在 ,但它很脆弱,因为如果你添加另一个关键字参数或迁移到Python 3它会破坏。
请注意,您必须使用different sentinel if None
is a valid value。
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')
一般情况下,我试图远离使用**kwargs
,除非我将关键字参数传递给另一个函数。如果您使用**kwargs
,则可以拨打set_value(dolar=5)
,但不要注意到拼写错误的“美元”。
另请注意,引发的正确例外是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')
但我可能不会使用单独的关键字参数:
Value = collections.namedtuple('Value', 'currency amount')
def set_value(country, value):
...
set_value(country, Value('USD', Decimal('15.30'))
答案 2 :(得分:0)
您可以使用dict.pop
:
def set_value(country, **kwargs):
euros = kwargs.pop('euro', None)
dollars = kwargs.pop('dollar', None)
if (euros is None is dollars) or (euros is not None is not dollars):
raise ValueError('One keyword argument is required: dollar=x or euro=x')
elif euros:
#do something
else:
#do something