Python 仅当字典中存在键时才对值执行操作
我有以下片段,其中我找不到明确的获胜者。 你推荐哪种款式?还有比这些更好的吗 (假设Python 仅当字典中存在键时才对值执行操作,python,dictionary,styles,Python,Dictionary,Styles,我有以下片段,其中我找不到明确的获胜者。 你推荐哪种款式?还有比这些更好的吗 (假设self.task.flags是一个字典) 中的和[] if 'target_names' in self.task.flags: foo(self.task.flags['target_names']) 这会两次提到字典和键的名称 我还可以想象,这会在内部执行两次相同的查找, 丢弃第一种情况下的值(中的) get和临时变量 value = self.task.flags.get('target_nam
self.task.flags
是一个字典)
中的和[]
if 'target_names' in self.task.flags:
foo(self.task.flags['target_names'])
这会两次提到字典和键的名称
我还可以想象,这会在内部执行两次相同的查找,
丢弃第一种情况下的值(
中的)
get
和临时变量
value = self.task.flags.get('target_names')
if value:
foo(value)
这消除了重复,但临时变量不是很优雅
当发生以下情况时,其含义也与其他含义略有不同
{'target\u names':None}
出现在self.task.flags
中foo
中引发的任何异常
而try
…除了
结构可能会在视觉上分散注意力;
当涉及到其他异常处理时,情况就更糟了# with impossibleValue being anything that can't possibly be one of your
# values, like self.task.flags or an Object created here and now, like i'll do now.
impossibleValue = Object()
# dict.get(key, defaultValue) returns dict[key] if key
# is in dict, otherwise returns defaultValue.
value = self.task.flags.get('target_names', impossibleValue)
if value != impossibleValue:
foo(value)
丑陋的方式:
# with impossibleValue being anything that can't possibly be one of your
# values, like self.task.flags or an Object created here and now, like i'll do now.
impossibleValue = Object()
# dict.get(key, defaultValue) returns dict[key] if key
# is in dict, otherwise returns defaultValue.
value = self.task.flags.get('target_names', impossibleValue)
if value != impossibleValue:
foo(value)
真的,这取决于你。没有实质性的性能差异,主要担心的是小心第二种形式。如果您的值为null,因此它们不会触发“If/then”子句,那么您将错误地认为没有键
a = {k:k**2 for k in range(1000000)}
def nullfunc(*args, **kwargs):
del args, kwargs
def infunc(a):
if 5000 in a:
nullfunc(a[5000])
def getvalue(a):
value = a.get(5000)
if value:
nullfunc(value)
def tryexcept(a):
try:
nullfunc(a[5000])
except KeyError:
pass
In [12]: %timeit infunc(a)
1000000 loops, best of 3: 238 ns per loop
In [13]: %timeit getvalue(a)
1000000 loops, best of 3: 256 ns per loop
In [14]: %timeit tryexcept(a)
1000000 loops, best of 3: 197 ns per loop
In [15]:
真的,这取决于你。没有实质性的性能差异,主要担心的是小心第二种形式。如果您的值为null,因此它们不会触发“If/then”子句,那么您将错误地认为没有键
a = {k:k**2 for k in range(1000000)}
def nullfunc(*args, **kwargs):
del args, kwargs
def infunc(a):
if 5000 in a:
nullfunc(a[5000])
def getvalue(a):
value = a.get(5000)
if value:
nullfunc(value)
def tryexcept(a):
try:
nullfunc(a[5000])
except KeyError:
pass
In [12]: %timeit infunc(a)
1000000 loops, best of 3: 238 ns per loop
In [13]: %timeit getvalue(a)
1000000 loops, best of 3: 256 ns per loop
In [14]: %timeit tryexcept(a)
1000000 loops, best of 3: 197 ns per loop
In [15]:
第一个和第三个选项对我都有意义。我更愿意保留try/except,用于实际异常的情况,而不是预期的结果(例如用户错误)。如果国旗不经常出现在那里有意义的话,我个人更喜欢案例1。如果不存在标志,则没有代码要执行,则执行相反的操作也是有意义的,即:
def foo(self, some_other_args):
... do something ...
if 'target_names' not in self.task.flags:
# Nothing further to do here, so return the result
return result
... do something with self.task.flags['target_names'] ...
return result
然而,我知道有些人喜欢避免那样的多重回报。如果您真的希望字典中出现“target_names”,我认为您的案例3可能是更好的解决方案,因为它明确了目的(缺少的键是真正例外的,而不是标准案例)。第一个和第三个选项对我来说都很有意义。我更愿意保留try/except,用于实际异常的情况,而不是预期的结果(例如用户错误)。如果国旗不经常出现在那里有意义的话,我个人更喜欢案例1。如果不存在标志,则没有代码要执行,则执行相反的操作也是有意义的,即:
def foo(self, some_other_args):
... do something ...
if 'target_names' not in self.task.flags:
# Nothing further to do here, so return the result
return result
... do something with self.task.flags['target_names'] ...
return result
然而,我知道有些人喜欢避免那样的多重回报。如果您真的希望字典中出现“target_names”,我认为您的案例3可能是更好的解决方案,因为它明确了意图(缺少的键是真正例外的,而不是标准案例)。第三种方式,因为正如您所说,它符合EAFP 请注意,在本例中,try/except子句可以写得更简洁(Python 3.4+):
第三种方法,正如你所说,它符合EAFP 请注意,在本例中,try/except子句可以写得更简洁(Python 3.4+):
这完全取决于上下文。在不同的情况下,其中一种方法会比其他方法更优雅。第二种假设不是很好,因为如果值为False或None,或“”、0或任何null值,它将错误地不会触发函数调用。第二种方法只有在你知道值的可能范围时才有效。@AlexanderHuszagh:谢谢;我已经说明了其含义上的差异,尽管它没有包括其他假值(
false
,0
,'
)。但实际上,这是你想要的。上下文决定一切。我不建议选择2,但是。。。上下文很重要。@AlexanderHuszagh:谢谢。我应该补充一点,在最初的上下文中,我们可以安全地假设字典中的值不是假的foo(value)
实际上类似于args.append('--target\u names=%s'%value)
。它完全取决于上下文。在不同的情况下,其中一种方法会比其他方法更优雅。第二种假设不是很好,因为如果值为False或None,或“”、0或任何null值,它将错误地不会触发函数调用。第二种方法只有在你知道值的可能范围时才有效。@AlexanderHuszagh:谢谢;我已经说明了其含义上的差异,尽管它没有包括其他假值(false
,0
,'
)。但实际上,这是你想要的。上下文决定一切。我不建议选择2,但是。。。上下文很重要。@AlexanderHuszagh:谢谢。我应该补充一点,在最初的上下文中,我们可以安全地假设字典中的值不是假的foo(value)
实际上类似于args.append('--target\u names=%s'%value)
。如果您打算建议这种方法,那么至少可以通过演示如何创建不可能的值来实现。。。最简单的方法是使用sentinel=object()
来保证一个唯一的对象,然后使用身份检查,例如如果值不是sentinel
…虽然这个答案可能是正确和有用的,但最好在回答的同时附上一些解释来解释它如何帮助解决问题。这在将来变得特别有用,如果有一个变化(可能无关)导致它停止工作,用户需要了解它曾经是如何工作的。注意,如果你要建议这种方法,那么至少通过演示如何创建I