2011-05-30 54 views
1

什么是Pythonic这样做的方式?从可能缺失的字典值初始化Python变量

value = (mydict.has_key('index') and mydict['index']) or 1024 

初始化从字典的值,如果存在的话,否则使用默认值。

上了车LBYL和EAFP一些答案,但过于冗长的代码:P

我想要一些单行初始化。

PS:蟒蛇 - 2.4只(运行CentOS5)

+0

实际上,您的代码执行此操作:“从dict的值初始化,如果存在,*不认为是布尔值False *,否则使用默认值。 – martineau 2011-05-31 01:08:43

+0

对!忘了说'索引'从来没有布尔(代码约束)对不起。 – Caruccio 2011-05-31 21:07:16

+1

如果它们实际上是一个布尔类型就没关系,因为在Python中有很多东西,比如'None','()','[]','''','{}','0',如果在逻辑表达式中使用'0.0',则认为'False' - 有些人称其为“真实性”(http://en.wikipedia.org/wiki/Truthiness)。 – martineau 2011-06-01 00:32:28

回答

11
value = mydict.get('index', 1024) 

(请注意,这是不完全等同于你的代码,因为它会使用1024只有在关键index不存在,而你的代码还采用1024当对应于关键index值falsy从你的解释我推断前者是你真正想要什么)

+1

需要注意的是,由于python是一种非惰性语言,因此将评估“默认值”表达式是否实际最终使用它。 (与if语句不同,它不会对它进行评估) – ninjagecko 2011-05-30 23:45:13

+0

@ninjagecko是正确的 - 如果缺省值构造起来很昂贵,并且您关心性能,那么您将不想使用get/setdefault。在这种情况下,我经常使用'try:...除了KeyError:'成语,特别是如果我期望关键'未命中'是罕见的。 – Whatang 2011-05-31 00:11:19

+0

@ninjagecko,Whatang:'value = mydict ['index']如果'index'在mydict else 1234'是懒惰的线索。我只想说清楚它在这里并不重要,因为1234创建起来非常便宜。 – 2011-05-31 01:16:11

2

或者使用setdefault() - 像get(),但它返回之前将钥匙:

value = mydict.setdefault('index', 1024) 
+1

需要注意的是,由于python是一种非惰性语言,因此将评估“默认值”表达式是否实际最终使用它。 (与不会评估它的'if'语句相反) – ninjagecko 2011-05-30 23:45:21

1

getsetdefault方法是知道重要的是,他们应该在任何Python程序员的工具箱。

这样做的另一个重要方法是使用collections.defaultdict,因为那样你就可以在一个地方定义你的“默认”,而不必在任何使用字典的地方将它分散到整个代码中,即不要重复你自己。然后,如果您更改默认值,则不需要通过代码来查找所有这些获取和setdefaults。例如

>>> import collections 
>>> myDict = collections.defaultdict 
>>> myDict = collections.defaultdict(lambda : 1024) 
>>> myDict[0] += 1 
>>> print myDict[0], myDict[100] 
1025 1024 

因为您可以设置函数调用,您可以为自己的默认值做任何你喜欢的事情。如何为每个新密钥分配1到10之间的随机值?

>>> import collections 
>>> import random 
>>> myDict = collections.defaultdict(lambda : random.randint(1,10)) 
>>> print myDict[0], myDict[100] 
1 5 
>>> print myDict[0], myDict[100], myDict[2] 
1 5 6 

好的,这个例子有点做作,但我相信你可以想到更好的用途。假设你有一个昂贵的类来构建 - 只有当密钥不存在时才创建实例,与调用getsetdefault(例如,

>>> class ExpensiveClass(object): 
>>>  numObjects = 0 
>>>  def __init__(self): 
>>>   ExpensiveClass.numObjects += 1 
>>> 
>>> print ExpensiveClass.numObjects 
0 
>>> x = {} 
>>> x[0] = ExpensiveClass() 
>>> print ExpensiveClass.numObjects 
1 
>>> print x.get(0, ExpensiveClass()) 
<__main__.ExpensiveClass object at 0x025665B0> 
>>> print ExpensiveClass.numObjects 
2 
>>> ExpensiveClass.numObjects = 0 
>>> z = collections.defaultdict(ExpensiveClass) 
>>> print ExpensiveClass.numObjects 
0 
>>> print z[0] 
>>> <__main__.ExpensiveClass object at 0x02566510> 
>>> print ExpensiveClass.numObjects 
1 

注意,调用x.get构建了一个新的ExpensiveClass实例,即使我们永远不要使用实例,因为x[0]已经存在。如果您确实要计算ExpensiveClass对象的数量,或者它们创建速度很慢,则这可能会导致问题。这些问题不会发生在collections.defaultdict

+0

另外值得注意的是,'setdefault()'和'defaultdict'都具有将任何缺少的键添加到字典的副作用。当使用'defaultdict'时,如果您希望默认值因键而异(因为工厂函数未通过查找键),您可能需要的不仅仅是一个简单的* default_factory *函数。 – martineau 2011-05-31 00:57:17

+1

另外一件事情,'defaultdict'直到Python 2.5(并且OP使用2.4)才被添加。 – martineau 2011-05-31 01:11:17

+0

'defaultdict'看起来很神奇,因为它是懒惰的,所以lambda不会被评估,除非需要;希望我可以upvote更 – ninjagecko 2011-05-31 01:46:19

1

collections模块defaultdict类可能会有所帮助。不幸的是,它直到Python 2.5才被引入,并且它并不是,而是你的代码所做的。这里有几个不同点:

  • 它只提供当钥匙丢失,而不是当它的存在,但有考虑False值的值。
  • 如果查找的关键字丢失,它会将其添加到字典中并使用默认值并返回默认值。
  • 所有缺少的值都会得到相同的默认值。

如果这行你可以用这样的模仿精髓之一老年蟒蛇:

try: 
    from collections import defaultdict 
except ImportError: 
    class defaultdict(dict): 
     def __init__(self, default_factory=None, *a, **kw): 
      dict.__init__(self, *a, **kw) 
      self.default_factory = default_factory 

     def __getitem__(self, key): 
      try: 
       return dict.__getitem__(self, key) 
      except KeyError: 
       return self.__missing__(key) 

     def __missing__(self, key): 
      self[key] = value = self.default_factory() 
      return value 

一个更完整的仿真配方可在ActiveState。即使你有Python 2.5+,你也可能想要派生自己的类来定制,以获得你想要的确切行为。除了检查“假”真值并且可能不会在字典中添加任何缺少的值之外,还可以为它提供单独的与多个默认值对应的默认值的字典,而不是“一刀切”。有关的方法请参阅Is there a way to set multiple defaults on a Python dict using another dict?

+0

+1用于基本的回退实现。 – lambacck 2011-05-31 02:59:25