Интерполяция строк на Python
[EDIT 00]: я редактировал несколько раз сообщение и теперь даже название, пожалуйста, прочитайте ниже.
Я только что узнал о методе строковых форматов и его использовании со словарями, таких как vars()
, locals()
и globals()
, например:
name = 'Ismael'
print 'My name is {name}.'.format(**vars())
Но я хочу:
name = 'Ismael'
print 'My name is {name}.' # Similar to ruby
Итак, я придумал это:
def mprint(string='', dictionary=globals()):
print string.format(**dictionary)
Вы можете взаимодействовать с кодом здесь:
http://labs.codecademy.com/BA0B/3#:workspace
Наконец, мне бы хотелось, чтобы функция была в другом файле с именем my_print.py
, поэтому я мог сделать:
from my_print import mprint
name= 'Ismael'
mprint('Hello! My name is {name}.')
Но как сейчас, есть проблема с областями, как я могу получить пространство имен основного модуля в качестве словаря из импортированной функции mprint. (а не от my_print.py
)
Надеюсь, я заставил себя удержаться, если нет, попробуйте импортировать функцию из другого модуля. (трассировка находится в ссылке)
Он обращается к globals()
dict от my_print.py
, но, конечно, имя переменной не определено в этой области, любые идеи о том, как это сделать?
Функция работает, если она определена в том же модуле, но заметьте, как я должен использовать globals()
, потому что если бы я не получил только словарь со значениями в пределах mprint()
.
Я попытался использовать нелокальную и точечную нотацию для доступа к основным переменным модуля, но я все еще не могу понять.
[РЕДАКТИРОВАТЬ 01]: Думаю, я понял решение:
В my_print.py:
def mprint(string='',dictionary=None):
if dictionary is None:
import sys
caller = sys._getframe(1)
dictionary = caller.f_locals
print string.format(**dictionary)
В test.py:
from my_print import mprint
name = 'Ismael'
country = 'Mexico'
languages = ['English', 'Spanish']
mprint("Hello! My name is {name}, I'm from {country}\n"
"and I can speak {languages[1]} and {languages[0]}.")
Он печатает:
Hello! My name is Ismael, I'm from Mexico
and I can speak Spanish and English.
Как вы думаете, ребята? Это было сложно для меня!
Мне это нравится, гораздо читабельнее для меня.
[EDIT 02]: Я создал модуль с функцией interpolate
, класс interpolate
и попытку для метода класса interpolate
, аналогичного функции.
Он имеет небольшой набор тестов и документирован!
Я застрял в реализации метода, я не понимаю.
Здесь код: http://pastebin.com/N2WubRSB
Как вы думаете, ребята?
[ИЗМЕНИТЬ 03]: Хорошо. Я решил использовать только функцию interpolate()
.
В string_interpolation.py
:
import sys
def get_scope(scope):
scope = scope.lower()
caller = sys._getframe(2)
options = ['l', 'local', 'g', 'global']
if scope not in options[:2]:
if scope in options[2:]:
return caller.f_globals
else:
raise ValueError('invalid mode: {0}'.format(scope))
return caller.f_locals
def interpolate(format_string=str(),sequence=None,scope='local',returns=False):
if type(sequence) is str:
scope = sequence
sequence = get_scope(scope)
else:
if not sequence:
sequence = get_scope(scope)
format = 'format_string.format(**sequence)'
if returns is False:
print eval(format)
elif returns is True:
return eval(format)
Еще раз спасибо ребятам! Любые мнения?
[EDIT 04]:
Это моя последняя версия, у нее есть тест, docstrings и описаны некоторые ограничения, которые я нашел:
http://pastebin.com/ssqbbs57
Вы можете быстро протестировать код здесь:
http://labs.codecademy.com/BBMF#:workspace
И клонировать grom git repo здесь:
https://github.com/Ismael-VC/python_string_interpolation.git
Ответы
Ответ 1
Языковой дизайн - это не просто решение головоломок: ;)
http://www.artima.com/forums/flat.jsp?forum=106&thread=147358
Изменить: PEP-0498 решает эту проблему!
Класс Template
из модуля string
также выполняет то, что мне нужно (но больше похоже на метод строки format
), в конце он также имеет читаемость, которую я ищу, он также имеет рекомендуемую явную, он находится в стандартной библиотеке, а также может быть легко настроен и расширен.
http://docs.python.org/2/library/string.html?highlight=template#string.Template
from string import Template
name = 'Renata'
place = 'hospital'
job = 'Dr.'
how = 'glad'
header = '\nTo Ms. {name}:'
letter = Template("""
Hello Ms. $name.
I'm glad to inform, you've been
accepted in our $place, and $job Red
will ${how}ly recieve you tomorrow morning.
""")
print header.format(**vars())
print letter.substitute(vars())
Самое смешное, что теперь я больше люблю использовать {}
вместо $
, и мне по-прежнему нравится модуль string_interpolation
, с которым я столкнулся, потому что он меньше печатает, чем один в конечном итоге, LOL!
Запустите код здесь:
http://labs.codecademy.com/BE3n/3#:workspace
Ответ 2
Модули не разделяют пространства имен в python, поэтому globals()
для my_print
всегда будет globals()
файла my_print.py; в том месте, где фактически была определена функция.
def mprint(string='', dic = None):
dictionary = dic if dic is not None else globals()
print string.format(**dictionary)
Вы должны передать текущие глобальные модули модуля() явно, чтобы заставить его работать.
Ans не используют изменяемые объекты в качестве значений по умолчанию в функциях python, это может привести к неожиданным результатам. Вместо этого используйте None
как значение по умолчанию.
Простой пример для понимания областей в модулях:
file: my_print.py
x = 10
def func():
global x
x += 1
print x
file: main.py
from my_print import *
x = 50
func() #prints 11 because for func() global scope is still
#the global scope of my_print file
print x #prints 50
Ответ 3
Часть вашей проблемы - ну, причина ее не работает - выделена в этом вопросе.
Вы можете использовать свою функцию, передав globals()
в качестве второго аргумента mprint('Hello my name is {name}',globals())
.
Хотя это может быть удобно в Ruby, я бы посоветовал вам не писать Ruby на Python, если вы хотите максимально использовать язык.