Как найти имя переменной, которая была передана в функцию? - PullRequest
8 голосов
/ 13 января 2012

В C / C ++ я часто находил полезным при отладке определять макрос, скажем, ECHO(x), который выводит имя переменной и ее значение (то есть ECHO(variable) может вывести variable 7).Вы можете получить имя переменной в макросе, используя оператор 'stringification' #, как описано здесь .Есть ли способ сделать это в Python?

Другими словами, я хотел бы функцию

def echo(x):
    #magic goes here

, которая, если вызывается как foo=7; echo(foo) (или foo=7; echo('foo'), может быть), распечатал бы foo 7.Я понимаю, что это тривиально, если я передаю в функцию и переменную, и ее имя, но я часто использую такие функции во время отладки, и повторение всегда заканчивает тем, что раздражает меня.

Ответы [ 3 ]

7 голосов
/ 13 января 2012

Не совсем решение, но может быть удобно (в любом случае у вас есть echo('foo') в вопросе):

def echo(**kwargs):
    for name, value in kwargs.items():
        print name, value

foo = 7
echo(foo=foo)

ОБНОВЛЕНИЕ: Решение для echo(foo) с inspect

* * 1010

Выход:

foo 7
foo + bar 10
(foo + bar)*baz/(bar+foo) 11

У него наименьший вызов, но он чувствителен к переводу строк, например ::11015.

echo((foo + bar)*
      baz/(bar+foo))

Напечатает:

baz/(bar+foo)) 11
3 голосов
/ 13 января 2012

Вот решение, которое заставляет вас набрать немного больше для его вызова. Он опирается на встроенную функцию locals :

def print_key(dictionary, key):
    print key, '=', dictionary[key]


foo = 7
print_key(locals(), 'foo')

Также возможно echo с упомянутой вами семантикой, используя модуль inspect . Тем не менее, прочитайте предупреждения в документации по проверке. Это уродливый непереносимый хак (он работает не во всех реализациях Python). Обязательно используйте его только для отладки.

Идея состоит в том, чтобы заглянуть в locals вызывающей функции. Модуль проверки допускает только это: вызовы представляются объектами фрейма, связанными друг с другом атрибутом f_back. Доступны локальные и глобальные переменные каждого фрейма (также есть встроенные функции, но вам вряд ли придется их печатать).

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

import inspect

def echo(varname):
    caller = inspect.currentframe().f_back
    try:
        value = caller.f_locals[varname]
    except KeyError:
        value = caller.f_globals[varname]
    print varname, '=', value
    del caller

foo = 7
echo('foo')
3 голосов
/ 13 января 2012
def echo(x):
    import inspect
    print "{0}: {1}".format(x, inspect.stack()[1][0].f_locals[x])
y = 123
echo('y')
# 'y: 123'

Смотри также: https://stackoverflow.com/a/2387854/16361

Обратите внимание, что это может вызвать проблемы с GC: * ​​1005 *

http://docs.python.org/library/inspect.html#the-interpreter-stack

Это также отключит людей, которые были сожжены, когда возились с кадрами, и может оставить неприятный вкус во рту. Но это будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...