【问题标题】:Python "switch statement" and string formattingPython“switch 语句”和字符串格式化
【发布时间】:2010-09-24 01:19:27
【问题描述】:

我正在尝试做 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) 调用它,它会按预期工作,但是呃,如此丑陋和不直观......我显然在这里遗漏了一些东西。

感谢任何提示,在此先感谢。

【问题讨论】:

  • 这不是一个真正的 switch 语句问题,例如 this one。这是一个缺少项目的字典问题。

标签: python lambda switch-statement


【解决方案1】:

如果我理解正确,我会推荐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>")

或者,如果您希望它比简单的带有一个字符串的 lambda 更具可定制性,您可以定义自己的 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__ 功能已添加到python 2.5 中的标准dict 类中。所以更简单的方法甚至不涉及collections.defaultdict——只是子类dict

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

【讨论】:

  • +1。我试图记住我是如何实现 missing key 处理最后一次我需要这样做的。我终于查看了我的代码,确实使用了defaultdict__missing__
【解决方案2】:

我认为您希望描述字典仅包含格式字符串,例如:

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

然后你会有一个函数接收一个描述键和一个事件特定数据的字典,它会产生格式化的消息,比如:

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

事实上,我认为您编写示例的方式,token1 等将在声明 descriptions 时进行评估——当我假设您想要的是格式化消息时这些变量在不同时间的不同值。

【讨论】:

  • 那将是一个不错的解决方案。但是 eventDataDict 的问题如下:我可能有也可能没有从 token1 到 token4 的数据。 Token1 可能是玩家、部落或其他任何东西,具体取决于描述关键字。因此,对于每个描述键,eventDataDict 可能会有所不同,这让我们重新回到了开关上。我说清楚了吗?谢谢!
  • 如果您已经知道每条消息的映射,只需将%(tokenX)s 放入您的格式化字符串而不是%(player)s。似乎这是一个知道“令牌”映射到“字符串中的点”的地方。 (可能用return descriptions[key] % locals(),不知道你的数据是从哪里来的。)
  • 但我希望名字漂亮:(...文本将被翻译,所以输入 %(token1)s 会不直观,谢谢!
【解决方案3】:

认为你想要做的是添加另一个层,根据各种字典键的存在或不存在选择格式化程序。

所以你可以使用类似的东西

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

确定将使用哪种格式字符串。请注意,我使用的是与str.format 一起使用的new-style format strings,而不是旧式的。推荐它们而不是较旧的 template % data

然后要获得格式化功能,您可以这样做

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

然后调用

formatted_greeting = fmt(eventDataDict)

这不如没有default case 的case 语句;如果您需要,您可以将descriptions 的访问包装在try ... except KeyError 构造中,可能都在一个名为例如的函数中。 format_description。您可能希望继承 dict 并使其成为该类的方法,具体取决于您的代码结构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多