2011-05-30 51 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