Python“switch 语句”和字符串格式

发布于 2024-09-24 20:48:58 字数 608 浏览 1 评论 0 原文

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

任何提示表示赞赏,提前致谢。

I'm trying to do switch statement (with dictionary) and the answer needs to be a formatted string, so for example:

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

Now, this would work if those both tokens were always defined, which is not the case. Plus I believe it is formatting all the strings in the dictionary, which is not needed, it should only format the one that will be needed. So, I came up with this very unusual and partially dumb solution using lambda

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

Which I can then call with descriptions["player_joined_clan"](0), it will work as expected but ehh, so ugly and unintuitive... I'm clearly missing something here.

Any tips appreciated, thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风轻花落早 2024-10-01 20:48:58

如果我理解正确,我会推荐 collections.defaultdict
这实际上并不是我所说的“switch”语句,但我认为最终结果接近您正在寻找的结果。

我可以用完整的代码、数据和应用程序来最好地解释。
显然,关键行是 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

If I'm understanding correctly, I'd recommend a collections.defaultdict.
This isn't really what I'd call a "switch" statement, but I think the end result is close to what you're looking for.

I can best explain with full code, data, and application.
Obviously, the key line is the defualtdict line.

>>> 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>")

Or, if you want it more customizable than simply a lambda with one string, you can define your own defaultdict class, such as:

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

change the line to use your class instead of the default one:

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

and, voila, the output:

{'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>)

See the documentation for collections.defaultdict for more examples.

Edit:
I forgot that this __missing__ functionality was added to the standard dict class in python 2.5. So an even simpler approach doesn't even involve collections.defaultdict-- just subclass dict:

class my_defaultdict(dict):
    def __missing__(self, key):
        return '<unknown %s>' % key
甜`诱少女 2024-10-01 20:48:58

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

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

然后您将有一个接收描述键和特定于事件的数据的字典的函数,该函数将生成格式化的消息,例如

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

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

I would think that you want the descriptions dictionary to contain only the format strings, e.g.:

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

Then you'd have a function that received a description key and a dictionary of event-specific data, that would produce the formatted message, something like:

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

In fact, I think that the way you have written your example, token1 etc. would be evaluated at the time of the declaration of descriptions -- when I presume what you want is for the message to be formatted for different values of these variables at different times.

清泪尽 2024-10-01 20:48:58

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

因此,您可以使用类似的方法

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

来确定将使用哪种格式字符串。请注意,我使用的是与 新样式格式字符串 >str.format 而不是旧式的。推荐使用它们而不是旧的 template % data 模板。

然后要获得格式化函数,您可以执行

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

然后调用

formatted_greeting = fmt(eventDataDict)

这比 case 语句要差,因为没有 default case;如果您需要,可以将 descriptions 的访问包装在 try ... except KeyError 构造中,可能全部都在名为 <的函数中代码>格式描述。您可能希望子类化 dict 并使其成为该类的方法,具体取决于代码的结构。

I think what you want to do is add another layer that selects a formatter based on the presence or absence of the various dictionary keys.

So you could use something like

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

to establish which format string will be used. Note that I'm using the new-style format strings that work with str.format rather than the old-style ones. They're recommended over the older template % data ones.

And then to get a formatting function you can do

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

and then call

formatted_greeting = fmt(eventDataDict)

This is inferior to a case statement in that there's no default case; if you need that you could wrap the access of descriptions in a try ... except KeyError construct, probably all within a function called e.g. format_description. You might want to subclass dict and make this a method of that class, depending on how your code is structured.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文