2010-09-24 44 views
1

我試圖做switch語句(帶字典),答案必須是一個格式化字符串,因此,例如:Python的「switch語句」和字符串格式化

descriptions = { 
    'player_joined_clan': "%(player)s joined clan %(clan)s." % {"player": token1, "clan": token2}, 
    #etc... 
    } 

現在,這會工作,如果這兩個令牌總是被定義的,事實並非如此。另外我相信它正在格式化字典中的所有字符串,這是不需要的,它應該只格式化需要的字符串。所以,我使用lambda

descriptions = { 
    'player_joined_clan': lambda x: "%(player)s joined clan %(clan)s." % {"player": token1, "clan": token2}, 
    } 

,我可以再與descriptions["player_joined_clan"](0)調用想出了這個非常不尋常的,並部分地啞的解決方案,它將按預期工作,但EHH,這麼難看和不直觀的......我清楚地失蹤這裏的東西。

任何提示讚賞,在此先感謝。

+0

這是不是一個真正的switch語句的問題,如[這一個](http://stackoverflow.com/questions/374239 /爲什麼 - 犯規 - 蟒蛇具備-A-switch語句)。這是一個字典與遺漏項目的問題。 – snapshoe 2010-09-27 03:18:14

回答

3

如果我理解正確,我會推薦collections.defaultdict。 這實際上並不是我稱之爲「開關」的聲明,但我認爲最終結果與您正在尋找的內容非常接近。

我可以最好地解釋完整的代碼,數據和應用程序。 顯然,關鍵路線是取消線路。

>>> import collections 
>>> 
>>> descriptions = { 
...  'player_joined_clan' : '%(player)s joined clan %(clan)s', 
...  'player_left' : '%(player)s left', 
...  'player_hit_player' : '%(player)s (of %(clan)s) hit %(player2)s (of %(clan2)s)', 
...  } 
>>> 
>>> data = [ 
...  {'player': 'PlayerA'}, 
...  {'player': 'PlayerB', 'clan' : 'ClanB'}, 
...  {'clan' : 'ClanC'}, 
...  {'clan' : 'ClanDA', 'player2': 'PlayerDB'}, 
...  ] 
>>> 
>>> for item in data: 
...  print item 
...  item = collections.defaultdict(lambda : '"<unknown>"', **item) 
...  for key in descriptions: 
...   print ' %s: %s' % (key, descriptions[key] % item) 
...  print 
... 
{'player': 'PlayerA'} 
    player_joined_clan: PlayerA joined clan "<unknown>" 
    player_left: PlayerA left 
    player_hit_player: PlayerA (of "<unknown>") hit "<unknown>" (of "<unknown>") 

{'clan': 'ClanB', 'player': 'PlayerB'} 
    player_joined_clan: PlayerB joined clan ClanB 
    player_left: PlayerB left 
    player_hit_player: PlayerB (of ClanB) hit "<unknown>" (of "<unknown>") 

{'clan': 'ClanC'} 
    player_joined_clan: "<unknown>" joined clan ClanC 
    player_left: "<unknown>" left 
    player_hit_player: "<unknown>" (of ClanC) hit "<unknown>" (of "<unknown>") 

{'clan': 'ClanDA', 'player2': 'PlayerDB'} 
    player_joined_clan: "<unknown>" joined clan ClanDA 
    player_left: "<unknown>" left 
    player_hit_player: "<unknown>" (of ClanDA) hit PlayerDB (of "<unknown>") 

或者,如果你想讓它更加個性化不是簡單地用一個字符串拉姆達,您可以定義自己的defaultdict類,如:

class my_defaultdict(collections.defaultdict): 
    def __missing__(self, key): 
     return '<unknown %s>' % key 

行更改爲使用類,而不是默認之一:

#item = collections.defaultdict(lambda : '"<unknown>"', **item) 
item = my_defaultdict(**item) 

和,瞧,輸出:

{'player': 'PlayerA'} 
    player_joined_clan: PlayerA joined clan <unknown clan> 
    player_left: PlayerA left 
    player_hit_player: PlayerA (of <unknown clan>) hit <unknown player2> (of <unknown clan2>) 

{'clan': 'ClanB', 'player': 'PlayerB'} 
    player_joined_clan: PlayerB joined clan ClanB 
    player_left: PlayerB left 
    player_hit_player: PlayerB (of ClanB) hit <unknown player2> (of <unknown clan2>) 

{'clan': 'ClanC'} 
    player_joined_clan: <unknown player> joined clan ClanC 
    player_left: <unknown player> left 
    player_hit_player: <unknown player> (of ClanC) hit <unknown player2> (of <unknown clan2>) 

{'clan': 'ClanDA', 'player2': 'PlayerDB'} 
    player_joined_clan: <unknown player> joined clan ClanDA 
    player_left: <unknown player> left 
    player_hit_player: <unknown player> (of ClanDA) hit PlayerDB (of <unknown clan2>) 

有關更多示例,請參閱collections.defaultdict的文檔。

編輯:
我忘了,這__missing__功能被添加到標準dict類在Python 2.5。因此,一個更爲簡單的方法甚至不涉及collections.defaultdict - 只要繼承dict

class my_defaultdict(dict): 
    def __missing__(self, key): 
     return '<unknown %s>' % key 
+0

+1。我試圖記住我是如何實現的*丟失的鍵*處理最後一次需要做的事情。我終於看到了我的代碼,使用'defaultdict'和'__missing__'。 – 2010-09-25 00:05:47

1

我會認爲你想描述字典只包含格式化字符串,如:

descriptions = { 
    'player_joined_clan': "%(player)s joined clan %(clan)s.", 
    #etc... 
    } 

然後你必須接受一個描述鍵和特定事件數據的詞典功能,這將產生格式化的消息,像:

def getMessage(key, eventDataDict): 
    return descriptions[key] % eventDataDict 

其實,我覺得你寫你的榜樣的方式,token1等將在descriptions聲明的時間評估 - 當我推測什麼你想要的是在不同的時間爲消息格式化這些變量的不同值。

+0

這將是一個不錯的解決方案。但是eventDataDict的問題如下:我可能有也可能沒有從token1到token4的數據。根據描述關鍵字,Token1可能是玩家,家族或其他任何人。所以eventDataDict對於每個描述鍵都可能不同,這使我們回到了開關。我是否清楚自己?謝謝! – Clash 2010-09-24 01:36:13

+1

如果您已經知道每封郵件的映射,只需將'%(tokenX)s'放入您的格式化字符串中,而不是'%(player)s'。看起來這是知道「標記」到「在字符串中的位置」映射的地方。 (可能使用'返回描述[關鍵]%的當地人()',不知道你的數據的來源。) – 2010-09-24 01:52:26

+0

但我想的名字是相當:(... 文本將被翻譯,所以把%(token1)s設置爲不直觀,謝謝! – Clash 2010-09-24 01:55:10

1

認爲你想要做的是添加另一個層,根據是否存在各種字典鍵來選擇格式化程序。

所以,你可以使用類似

formatters = { 
    set('player', 'team'): "{player} joined {team}".format, 
    set('player'): "Hello {player}.".format, 
    set('team'): "{team} FTW!".format, 
    set(): "Something happened.".format} 

確定哪些格式字符串將被使用。請注意,我使用的new-style format stringsstr.format配合使用,而不是舊式。推薦使用舊版的template % data

然後得到一個格式化功能,你可以做

fmt = descriptions[set(eventDataDict.keys())] 

,然後調用

formatted_greeting = fmt(eventDataDict) 

這是不如在一個case語句沒有default情況;如果你需要的話,你可以將descriptions的訪問包裝在try ... except KeyError結構中,可能全部在一個稱爲例如format_description。您可能想要子類dict,並根據您的代碼的結構,使其成爲該類的一種方法。