Форматирование строк в Python - PullRequest
5 голосов
/ 20 августа 2011

В последнее время я много занимаюсь программированием на основе музыки, и поэтому я часто занимаюсь такими вещами, чтобы справиться с отсутствующими метаданными в некоторых песнях:

default = {'title': 'Unknown title', 'artist': 'unknown Artist'}
default.update(song)
print '{title} - {artist}'.format(**default)

Есть ли более чистый способ сделать это? Я попытался переопределить __missing__, например, но отсутствующие ключи все еще выдают KeyError:

class Song(dict):
    # dictionary with some nice stuff to make it nicer

    def __missing__(self, key):
        return 'Unknown {key}'.format(key = key)

Редактировать: Извините, я должен был быть более ясным, в основном следующее должно работать.

s = Song()
print '{notAKey}'.format(s)

Несколько человек отметили, что ** не нужны.

Редактировать 2: Я «решил» мою проблему, по крайней мере, к моему удовлетворению. Это спорный вопрос, является ли это чище, но это работает для меня.

from string import Formatter

class DefaultFormatter(Formatter):

    def get_value(self, key, args, kwargs):
        # Try standard formatting, then return 'unknown key'

        try:
            return Formatter.get_value(self, key, args, kwargs)
        except KeyError:
            return kwargs.get(key, 'Unknown {0}'.format(key))

class Song(dict):

    def format(self, formatString):
        # Convenience method, create a DefaultFormatter and use it

        f = DefaultFormatter()
        return f.format(formatString, **self)

Таким образом, следующее вернет 'Unknown notAKey'

k = Song()
print k.format('{notAKey}')

Ответы [ 5 ]

6 голосов
/ 20 августа 2011

Краткое содержание : инкапсулировать песню в классе.

Мне кажется, что песня является основным типом данных в вашем коде и достойна того, чтобы иметь выделенный класс для представления.Это.Во что бы то ни стало используйте внутренний диктат класса для хранения данных, но попытайтесь перейти на более высокий уровень абстракции, чем диктат.

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

Что касается реализации форматирования, то не имеет значения, является ли это немного затянуто, поскольку вы пишете это в одном месте.только.

3 голосов
/ 20 августа 2011

Предупреждение. На самом деле это решение не помогает решить первоначальный вопрос относительно '{title} - {artist}'.format(**default)

Вы пытались импортировать defaultdict из collections?

from collections import defaultdict

class Song(defaultdict):
    def __missing__(self, key):
        return 'Unknown {key}'.format(key = key)

Вот похожий вопрос: Как создать словарь python, который возвращает ключ для ключей, отсутствующих в словаре, вместо вызова KeyError? :

1 голос
/ 20 августа 2011

К сожалению, когда вы вызываете метод с синтаксисом **foo, он конвертирует foo просто в обычный dict. Вероятно, самое чистое решение - это то, которое вы опубликовали в своем первом фрагменте.

0 голосов
/ 20 августа 2011

Хорошо, один вариант, который я могу придумать, - это использовать метод, который по своей сути может предоставить вам значения по умолчанию, а именно getattr. Если бы вы преобразовали ваш диктант в объект, превращающий ключи в атрибуты, вы можете использовать сейф getattr для получения значений:

class AttributeDict(): 
    def __init__(self, source_dict):
        self._ATTRIBUTE_DICT_source_dict = source_dict
        for key in source_dict.keys():
            setattr(self, str(key), source_dict[key])

Теперь вы можете просто использовать:

song = AttributeDict(song)
artist = getattr(song, 'artist', 'Unknown Artist')
0 голосов
/ 20 августа 2011

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

>>> class Song(dict):
...     def __getitem__(self, key):
...             if key in self.keys(): return super(Song, self).__getitem__(key)
...             return 'Unknown {key}'.format(key=key)
... 
>>> s = Song()
>>> s['foo']
'Unknown foo'
>>> s['foo'] = 1
>>> s['foo']
1
...