Получение шаблона ** vars () в форматировании строки - PullRequest
3 голосов
/ 04 февраля 2010

Я часто использую следующий шаблон для форматирования строк.

a = 3
b = 'foo'
c = dict(mykey='myval')

#prints a is 3, b is foo, mykey is myval
print('a is {a}, b is {b}, mykey is {c[mykey]}'.format(**vars()))

То есть у меня часто есть значения, которые мне нужно напечатать в локальном пространстве имен, представленном вызовом vars (). Однако, когда я просматриваю свой код, мне кажется, что это ужасно бессмысленно постоянно повторять шаблон .format(**vars()).

Я хотел бы создать функцию, которая будет захватывать этот шаблон. Это было бы что-то вроде следующего.

# doesn't work
def lfmt(s):
    """
    lfmt (local format) will format the string using variables
    in the caller's local namespace.
    """
    return s.format(**vars())

За исключением того, что к тому времени, когда я нахожусь в пространстве имен lfmt, vars () уже не то, что я хочу.

Как я могу написать lfmt, чтобы он выполнял vars () в пространстве имен вызывающего, чтобы следующий код работал в качестве примера выше?

print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}'))

Ответы [ 5 ]

2 голосов
/ 04 февраля 2010

Редактировать : чтобы lfmt работал при вызове из разных пространств имен, вам потребуется модуль inspect. Обратите внимание, что как документация предупреждает , модуль inspect может не подходить для производственного кода, так как он может не работать со всеми реализациями Python

import inspect
def lfmt(s):
    caller = inspect.currentframe().f_back
    return s.format(**caller.f_locals)

a = 3
b = 'foo'
c = dict(mykey='myval')

print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}'))
# a is 3, b is foo, mykey is myval
1 голос
/ 04 февраля 2010

Вы должны проверить переменные из вызывающих фреймов.

Это поможет вам начать:

import inspect
import pprint

def lfmt(s):
    for frame in inspect.getouterframes(inspect.currentframe()):
        f = frame[0]
        print pprint.pformat(f.f_locals)
    return '???'

if __name__ == '__main__':
    a = 10
    b = 20
    c = 30
    lfmt('test')
0 голосов
/ 16 мая 2013

Вы также можете использовать sys вместо inspect, но я не знаю, есть ли у него такая же проблема с различными реализациями, как у inspect.

import sys

def lfmt(s):
    caller = sys._getframe(1)
    return s.format(**caller.f_locals)

Насколько я понял: Реализация интерполяции строки Python

0 голосов
/ 04 февраля 2010

Так плохо набирать ,vars каждый раз, когда вы вызываете функцию?

def lfmt(s,v):
    """
    lfmt (local format) will format the string using variables
    from the dict returned by calling v()"""
    return s.format(**v())

print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}',vars))
0 голосов
/ 04 февраля 2010

Вот вы:

import sys

def lfmt(s):
    """
    lfmt (local format) will format the string using variables
    in the caller's local namespace.
    """

    if hasattr(sys, "tracebacklimit") and sys.tracebacklimit == 0:
        raise Exception, "failfailfail"

    try:
        raise ZeroDivisionError
    except ZeroDivisionError:
        f = sys.exc_info()[2].tb_frame.f_back

    return s.format(**f.f_locals)

a = 5
somestring = "text"
print lfmt("{a} {somestring}")

Тот факт, что это работает, не означает, что вы должны его использовать. Это то, что разработчики называют «основным взломом», обычно поставляется с комментарием «XXX fix me XXX».

...