我应该通过以下说法来说明这一点:我知道默认情况下不支持此功能 - 我正在尝试的是一种实用性很少的hacky解决方法,并且是精神手淫的完整练习,因为无聊和好奇心。那就是说,我正在努力做到以下几点:
基于以下Python代码,
with BuildFile('mybuild.build') as buildfile:
objdir = 'obj'
我想生成一个文件mybuild.build
,内容为:
objdir = obj
理想情况下,我想在创建点关联变量名称,这样如果我在objdir = 'obj'
之后设置断点,我希望能够执行以下操作:< / p>
>>> print repr(objdir)
'objdir = obj'
然而,使用内置功能是不可能的,因为无法覆盖从语法中推断出的类型。我可能最终在使用BuildFile.__enter__
方法的ctypes
方法中修复了一种变通方法,以便对基础tp_new
结构上的tp_dict
或PyTypeObject
字段进行修补(以及随后在退出时恢复该覆盖),但为了简单起见,我们假设我没有关联变量名称,直到我到达BuildFile.__exit__
方法。
我想知道的是以下内容:
是否内置Python功能可以暂停执行,追溯到声明了局部变量的帧,并获取与变量关联的本地名称?
答案 0 :(得分:2)
实际上你可以像这样执行类似的技巧:
>>> from contextlib import contextmanager
>>> @contextmanager
def override_new_vars(locs):
old_locals = locs.copy()
yield
new_locals_names = set(locs) - set(old_locals)
for name in new_locals_names:
locs[name] = '%s = %r' % (name, locs[name])
>>> with override_new_vars(locals()):
c = 10
>>> c
'c = 10'
在你的情况下,它看起来像:
with BuildFile('mybuild.build') as buildfile, override_new_vars(locals()):
objdir = 'obj'
那是你想做的吗?
答案 1 :(得分:1)
Python没有可追踪框架的可移植方式......但CPython实现确实:sys._getframe
返回一个框架对象。
你可以用框架对象做什么?请参阅inspect
文档中有用的所有有趣内容的方便图表,但它们包括框架所见的locals()
和globals()
,以及框架中执行的代码对象 - 它本身包括本地名称,未绑定名称和闭包单元格。
但是,正如其他人所指出的那样,你并不需要这个框架;你需要的只是本地人,而且只是明确地将它传递给你的上下文管理器就更简单了。
如果你真的想这样做:
import contextlib
import sys
@contextlib.contextmanager
def dumping():
f = sys._getframe(2)
fl = f.f_locals.copy()
try:
yield None
finally:
for name, value in f.f_locals.items():
if name not in fl:
print('{} = {}'.format(name, value))
bar = 0
def foo():
global bar
bar = 3
baz = 4
qux = 5
with dumping():
spam = 'eggs'
eggs = 3
bar = 4
baz = 5
foo()
运行时,应该打印:
eggs = 3
spam = eggs
换句话说,只有在with
块内声明的新变量的名称和值 - 我认为,你想要的是什么,对吗?
如果你想要新的和反弹的本地人,你可能想要存储这样的东西:
fl = {(name, id(value)) for name, value in f.f_locals.items()}
当然你也可以重新绑定nonlocals和globals,所以如果你关心它,也要隐藏全局变量(但确保检查locals is globals
是否有模块级代码),或者走一下闭包。 / p>
如果您正在使用CPython 2(为什么?对于真正的项目,它有时是有意义的,但要了解内部如何工作以获得乐趣?然而,有些人......),相同的代码将起作用。属性名称可能略有不同,但您可以通过转出框架和代码的dir
来猜测它们。显然你想要2.x print
语法。
它也适用于PyPy,至少2.0b。
如果你想知道我怎么知道使用_getframe(2)
......我没有。我很确定它会是1帧或2帧,可能只有3帧,但是哪一帧?所以我就这样做了:
@contextlib.contextmanager
def dumping():
for i in range(4):
f = sys._getframe(i)
print(f.f_code.co_filename, f.f_code.co_firstlineno, f.f_lineno)
0当然是dumping
本身; 1是contextlib.contextmanager
中的包装函数; 2是呼叫帧; 3是模块顶层。一旦你想到这一点就很明显,但直到我知道答案才明白。 :)
答案 2 :(得分:0)
我想你可以试试这个:
from copy import copy
objdir = 'obj'
def get_variable_name(variable):
if variable:
variables = copy(locals())
for i in variables:
if variables.get(i) == variable:
res = i + '=' + variables.get(i)
return res
使用此应该可以解决问题,我自己测试了这段代码。