Python «оператор switch» и форматирование строки - PullRequest
1 голос
/ 24 сентября 2010

Я пытаюсь сделать оператор switch (со словарем), и ответ должен быть отформатированной строкой, например:

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

Теперь, это сработало бы, если бы оба этих токена были всегда определены, что не так. Плюс я считаю, что это форматирование всех строк в словаре, которое не нужно, оно должно форматировать только ту, которая будет нужна. Итак, я придумал это очень необычное и частично глупое решение с использованием лямбды

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

Который я могу затем назвать descriptions["player_joined_clan"](0), он будет работать, как и ожидалось, но эх, так уродливо и не интуитивно ... Я явно что-то здесь упускаю.

Любые советы приветствуются, заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 24 сентября 2010

Если я правильно понимаю, я бы порекомендовал collection.defaultdict .На самом деле это не то, что я бы назвал выражением «switch», но я думаю, что конечный результат близок к тому, что вы ищете.

Я могу лучше всего объяснить с полным кодом, данными и приложением,Очевидно, что ключевой строкой является строка defualtdict.

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

См. Документацию по collection.defaultdict для дополнительных примеров.

Редактировать:
Я забыл, что эта функциональность __missing__ была добавлена ​​к стандартному классу dict в Python 2.5.Таким образом, даже более простой подход даже не включает collections.defaultdict - просто подкласс dict:

class my_defaultdict(dict):
    def __missing__(self, key):
        return '<unknown %s>' % key
1 голос
/ 24 сентября 2010

I думаю , что вы хотите сделать, это добавить еще один слой, который выбирает средство форматирования в зависимости от наличия или отсутствия различных словарных ключей.*

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)

Thisуступает заявлению case в том, что нет default case;если вам нужно, вы можете обернуть доступ к descriptions в конструкцию try ... except KeyError, возможно, все внутри функции, которая называется, например, format_description.Возможно, вы захотите создать подкласс dict и сделать его методом этого класса, в зависимости от структуры вашего кода.

1 голос
/ 24 сентября 2010

Я думаю, вы хотите, чтобы словарь описаний содержал только строки формата, например:

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

Тогда у вас была бы функция, которая получила ключ описания и словарь данных, относящихся к событию., это приведет к форматированному сообщению, что-то вроде:

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

На самом деле, я думаю, что способ, которым вы написали свой пример, token1 и т. д., будет оцениваться во время объявления descriptions - когда я предполагаю, что вы хотите, чтобы сообщение было отформатировано для разных значений этих переменных в разное время.

...