Как распечатать переменные аргументы с именами из предыдущего стека?

Я хотел бы определить функцию журнала, которая вызывается с сообщением, за которым следует одна или несколько переменных для печати. Итак, что-то вроде следующего:

log( "Oh no, error.", x, d)

log будет определен примерно так:

def log( msg, *arg):
    # Loop through arg, printing caller's variable's name and value.

Это запишет в файл следующее:

Oh no, error.
    x = 5
    d = { foo: "Foo", goo: "Goo" }

Это вообще можно сделать? Я могу печатать локальные переменные и аргументы, используя inspect, но я не знаю, могу ли я перебирать значения в текущем кадре, используя имена переменных предыдущего кадра. (locals в inspect.getargvalues(previousFrame) есть имена, но есть и много других имен.)


person Bitdiot    schedule 15.09.2015    source источник
comment
Как вы однозначно определяете имена переменных? Что, если у вызывающего объекта в пространстве имен было y, а его значение также оказалось 5? Что, если вызывающая сторона передает что-то вроде d['foo']? Вам нужно произвольно глубоко рекурсивно обращаться к объектам в пространстве имен вызывающей стороны? Что, если они передают результат вызова функции? log('message', x.bar())? Есть много случаев, которые довольно трудно разрешить здесь... хотя вы, вероятно, могли бы проверить стек и распечатать все локальные переменные вызывающей стороны.   -  person mgilson    schedule 15.09.2015
comment
вздох Да, наверное, ты прав, мгилсон. И что я должен делать? Должен ли я удалить этот пост? Или, может быть, это мое принятие желаемого за действительное, мне просто нужна функция журнала, которая регистрирует переменные, которые я ей даю. Это вообще нельзя делать? Итак, если они передают ему 5, он печатает 5 = 5. Если они передают ему y, он печатает y = 5. Если они передают ему объект, он печатает object = str(object).   -  person Bitdiot    schedule 15.09.2015
comment
@ Битдиот, почему? Она не плохо написана и не плохо организована. И лично для меня вопрос интересен   -  person ForceBru    schedule 15.09.2015


Ответы (2)


Я думаю, вы можете использовать что-то вроде этого:

определение

def log(msg, **kwargs):
    print(msg)
    for key, value in kwargs.items():
        print('{0} = {1}'.format(key,value))

определение (если порядок обязателен)

def log(msg, **kwargs):
    print(msg)
    for key, value in sorted(kwargs.items()):
        print('{0} = {1}'.format(key,value))

Применение

msg='Oh no, error'
log(msg, x=5, y=6)

выход

Oh no, error
y = 6
x = 5
person jlnabais    schedule 15.09.2015
comment
Это хорошо, так как не использует черную магию. Также явное лучше, чем неявное. - person Yaroslav Admin; 15.09.2015
comment
Обратите внимание, что порядок аргументов не обязательно такой, как вы ожидаете... through-kwargs" title="в python что определяет порядок при переборе kwargs"> stackoverflow.com/questions/8977594/ - person Karoly Horvath; 15.09.2015
comment
Вы правы, я не учел здесь порядок, надо было указать на то, что словари неупорядочены. Я отредактировал ответ. - person jlnabais; 15.09.2015

Это может быть очень грязно и может не работать время от времени (это происходит на моей машине), но, похоже, это помогает.

Более того, ему не нужны все эти **keargs фокусы. Вы просто звоните log('Message',as,many,args,as,you,want) и все.

import inspect, gc

def log(msg,*args):
    #This gets the source code line that has to do with args
    #I mean, that calls log
    code=''.join(inspect.getframeinfo(gc.get_referrers(args)[0].f_back).code_context).strip()
    #get the arguments (except msg)
    c=code.split('log')[1].strip()
    c=c.replace('(','').replace(')','')
    c=c.split(',')[1:]
    if c[-1].endswith(';'):
        c[-1]=c[-1].replace(';','')

    for x in xrange(0,len(c)):
        print c[x],'=',args[x]


a=5; b='hello'

print 'test'

log('hello',a,b);

print 'hello'

Даже если log запускается из другой функции, все в порядке.

person ForceBru    schedule 15.09.2015
comment
Я попробовал это. Действительно изящно выглядящий код, но если журнал занимает несколько строк, он, кажется, спотыкается. Мне это все еще нравится, но я думаю, что склоняюсь к решению key=val. - person Bitdiot; 16.09.2015