MyTetra Share
Делитесь знаниями!
Интерполяция строк
09.08.2018
00:14
Раздел: Python


Интерполяция строк

Все хорошо знают об операторе форматирования в языке Python. В этой заметке приводятся малоизвестные приемы его использования.

В самом простом способе применения оператора форматирования его поведение аналогично функций *printf в C:

  1. >>> print 'Длина удава: %d попугаев и %d попугайское крылышко' % (38, 1)
  2. Длина удава: 38 попугаев и 1 попугайское крылышко


При использовании ‘%s’ или ‘%r’ объекты любого типа автоматически преобразуются к строке, как если бы к ним применялась функция str или repr соответственно:

  1. >>> print 'Длина удава: %s попугаев и %s попугайское крылышко' % (38, 1)
  2. Длина удава: 38 попугаев и 1 попугайское крылышко


Для длинных строк с большим количеством параметров удобнее ссылаться на значения по имени. Это позволит менять порядок следования значений в строке не меняя правый аргумент оператора форматирования:

  1. >>> args = {'parrots': 38, 'wings': 1}
  2. >>> print '%(parrots)s попугаев и %(wings)s попугайское крылышко' % args
  3. 38 попугаев и 1 попугайское крылышко
  4. >>> print '%(wings)s крылышко в добавок к %(parrots)s попугаям' % args
  5. 1 крылышко в добавок к 38 попугаям
  6. >>> print '%(wings)s крылышко не в счет' % args
  7. 1 крылышко не в счет


Можно не составлять словарь самостоятельно, а использовать функцию globals, locals или vars:

  1. >>> print '%(parrots)s попугаев и %(wings)s попугайское крылышко' % vars()
  2. 38 попугаев и 1 попугайское крылышко


Однако и это не все, что можно делать с оператором форматирования. Тем, кто знаком с языком perl, обычно сильно не достает интерполяции строк с выражениями, записанными непосредственно в строке-шаблоне. Аналогичный эффект можно получить и в языке Python с помощью простого классом, имитирующего поведение словаря:

  1. class EvalDict:
  2.     def __getitem__(self, key):
  3.         return eval(key)


Использовать класс EvalDict можно аналогично функции vars:

  1. >>> nums = [38, 1]
  2. >>> print '%(nums[0])s попугаев и %(nums[1])s крылышко' % EvalDict()
  3. 38 попугаев и 1 крылышко


Приведенный класс EvalDict обладает двумя недостатками. Во-первых, он ищет значения переменных только в глобальном пространстве имен модуля, в котором он определен. Во-вторых, он не будет обрабатывать вложенные выражения. Исправим эти недостатки.

  1. import sys
  2.  
  3. class EvalDict:
  4.  
  5.     def __init__(self, globals=None, locals=None):
  6.         if globals is None:
  7.             globals = sys._getframe(1).f_globals
  8.         self.globals = globals
  9.         if locals is None:
  10.             locals = sys._getframe(1).f_locals
  11.         self.locals = locals
  12.  
  13.     def __getitem__(self, key):
  14.         key = key % self
  15.         return eval(key, self.globals, self.locals)


Теперь определение класса можно спокойно вынести в отдельный модуль и использовать вложенные выражения:

  1. >>> nums = [38, 1]
  2. >>> units = ['попугаев', 'крылышко']
  3. >>> index = 0
  4. >>> print '%(nums[index])d %(units[index])s' % EvalDict()
  5. 38 попугаев
  6. >>> index = 1
  7. >>> print '%(nums[index])d %(units[index))s' % EvalDict()
  8. 1 крылышко


Так же в этом разделе:
 
MyTetra Share v.0.52
Яндекс индекс цитирования