Является ли форматировщик строк, который тянет переменные из его вызывающей области плохой практики?

У меня есть код, который делает очень много форматирования строк. Часто я получаю код в строках:

"...".format(x=x, y=y, z=z, foo=foo, ...) 

Где я пытаюсь интерполировать большое количество переменных в большую строку.

Есть ли хорошая причина не писать такую ​​функцию, которая использует модуль inspect для поиска переменных для интерполяции?

 import inspect def interpolate(s): return s.format(**inspect.currentframe().f_back.f_locals) def generateTheString(x): y = foo(x) z = x + y # more calculations go here return interpolate("{x}, {y}, {z}") 

  • Цель else и, наконец, обработка исключений
  • Разделить строку на строки по длине?
  • Указание числа десятичных знаков в Python
  • Как удалить все объекты для модели NDB в Google App Engine для python?
  • конвертировать 64-битные окна даты в python
  • Google App Engine: как писать большие файлы в Google Cloud Storage
  • Библиотека Python для преобразования между префиксами SI
  • Python, создание объектов
  • 4 Solutions collect form web for “Является ли форматировщик строк, который тянет переменные из его вызывающей области плохой практики?”

    Более простым и безопасным подходом будет следующий код. index.currentframe не доступен для всех реализаций python, поэтому ваш код сломается, когда он не будет. В jython, ironpython или pypy это может быть недоступно, потому что это похоже на cpython. Это делает ваш код менее портативным.

     print "{x}, {y}".format(**vars()) 

    этот метод фактически описан в главе «Ввод и вывод» руководства Python

    Это также можно сделать, передав таблицу в качестве аргументов ключевого слова с помощью обозначения «**». Это особенно полезно в сочетании с новой встроенной функцией vars (), которая возвращает словарь, содержащий все локальные переменные.

    также в документах python для проверки.currentframe

    Подробности реализации CPython: эта функция зависит от поддержки фрейма стека Python в интерпретаторе, который не гарантированно существует во всех реализациях Python. Если запуск в реализации без поддержки фрейма стека Python, эта функция возвращает None.

    Обновление: Python 3.6 имеет эту функцию (более мощный вариант):

     x, y, z = range(3) print(f"{x} {y + z}") # -> 0 3 

    См. PEP 0498 – Интерполяция литеральных строк


    Это [ручное решение] приводит к несколько неожиданному поведению с вложенными функциями:

     from callerscope import format def outer(): def inner(): nonlocal a try: print(format("{a} {b}")) except KeyError as e: assert e.args[0] == 'b' else: assert 0 def inner_read_b(): nonlocal a print(b) # read `b` from outer() try: print(format("{a} {b}")) except KeyError as e: assert 0 a, b = "ab" inner() inner_read_b() 

    Примечание: тот же вызов выполняется успешно или не выполняется в зависимости от того, упоминается ли переменная где-то выше или ниже.

    Где callerscope :

     import inspect from collections import ChainMap from string import Formatter def format(format_string, *args, _format=Formatter().vformat, **kwargs): caller_locals = inspect.currentframe().f_back.f_locals return _format(format_string, args, ChainMap(kwargs, caller_locals)) 

    У хорошего старого почтальона есть функция _ которая делает именно эту вещь:

     def _(s): if s == '': return s assert s # Do translation of the given string into the current language, and do # Ping-string interpolation into the resulting string. # # This lets you write something like: # # now = time.ctime(time.time()) # print _('The current time is: %(now)s') # # and have it Just Work. Note that the lookup order for keys in the # original string is 1) locals dictionary, 2) globals dictionary. # # First, get the frame of the caller frame = sys._getframe(1) # A `safe' dictionary is used so we won't get an exception if there's a # missing key in the dictionary. dict = SafeDict(frame.f_globals.copy()) dict.update(frame.f_locals) # Translate the string, then interpolate into it. return _translation.gettext(s) % dict 

    Итак, если Барри Варшава может это сделать, почему мы не можем?

    В модуле inspect currentframe определяется следующим образом:

     if hasattr(sys, '_getframe'): currentframe = sys._getframe else: currentframe = lambda _=None: None 

    Поэтому, если sys имеет атрибут _getframe , функция interpolate не будет работать.

    Документы для sys._getframe говорят:

    Подробности реализации CPython: эта функция должна использоваться только для внутренних и специализированных целей. Он не гарантированно существует во всех реализациях Python.


    Письмо

     "{x}, {y}, {z}".format(**vars()) 

    в теле функции не так много дольше, чем

     interpolate("{x}, {y}, {z}") 

    и ваш код будет более переносимым.

    Python - лучший язык программирования в мире.