Можете ли вы перевести этот макрос отладки из C ++ в Python? - PullRequest
2 голосов
/ 31 марта 2011

Я использую этот очень полезный макрос при разработке на C ++:

#define DD(a) std::cout << #a " = [ " << a << " ]" << std::endl;std::cout.flush();

Не могли бы вы помочь мне реализовать ту же идею в Python? Я не знаю, как #a может быть реализован с помощью функции Python ...

Ответы [ 6 ]

7 голосов
/ 31 марта 2011

Как указывают @ Andrea Spadaccini и @ adirau , невозможно надежно отобразить значения обратно на имена переменных Python.Вы можете пройтись по всем пространствам имен, ища какое-нибудь имя переменной, которое ссылается на данное значение, но это будет бороться с системой и может вернуть неправильное имя переменной.

Гораздо проще просто передать имя переменной:

import inspect
def pv(name):
    frame,filename,line_number,function_name,lines,index=inspect.getouterframes(
        inspect.currentframe())[1]    
    # print(frame,filename,line_number,function_name,lines,index)
    val=eval(name,frame.f_globals,frame.f_locals)
    print('{0}: {1}'.format(name, val))


a=5
pv('a')

выход:

a: 5
6 голосов
/ 31 марта 2011

Вы можете проверить трассировку стека и "проанализировать" ее.Поскольку вы знаете имя своей функции (в данном случае dd), становится довольно легко найти вызов и извлечь имя переменной.

    import inspect
    import re

    def dd(value):
        calling_frame_record = inspect.stack()[1]
        frame = inspect.getframeinfo(calling_frame_record[0])
        m = re.search( "dd\((.+)\)", frame.code_context[0])
        if m:
            print "{0} = {1}".format(m.group(1), value)

    def test():
        a = 4
        dd(a)

    test()

Выход

a = 4
3 голосов
/ 31 марта 2011
import sys

def DD(expr):
    frame = sys._getframe(1)
    print '%s = %s' % (expr, repr(eval(expr, frame.f_globals, frame.f_locals)))

GLOBAL_VAR = 10

def test():
    local_var = 20
    DD('GLOBAL_VAR + local_var')


>>> test()
GLOBAL_VAR + local_var = 30
3 голосов
/ 31 марта 2011

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

>>> a=4
>>> locals()['a']
4

РЕДАКТИРОВАТЬ: подробное объяснение можно найти здесь

3 голосов
/ 31 марта 2011

Я думаю, что это невозможно сделать.

Макрос отладки, который вы опубликовали, работает, потому что он раскрывается перед компиляцией, во время предварительной обработки, когда вы знаете имя переменной. Как будто ты пишешь все эти cout самостоятельно.

Python не имеет препроцессора (AFAIK), есть внешние инструменты, которые делают аналогичные вещи (pyp и другие), но вы не можете определить макрос со стандартным языком.

Так что вы должны делать свой трюк во время выполнения. Ну, во время выполнения вы не знаете «имя» переменной, потому что переменная является просто ссылкой на объект, когда вы вызываете метод, который вызываете его для объекта, а не для «переменной». Может быть много переменных, которые указывают на этот объект, как объект узнает, какая переменная использовалась для вызова метода?

2 голосов
/ 30 августа 2013

Решение Rod идеально подходит для использования. Это может быть даже расширено для обработки многих переменных. Но вы можете приблизиться к этому с гораздо меньшим количеством магии:

def dd(**kwargs):
    print ", ".join(str(k) + "=" + str(v) for k, v in kwargs.iteritems())

a = 1
dd(a=a,b=3)

выход:

a=1, b=3
...