from collections import MutableMapping
class HistoryNamespace(MutableMapping):
def __init__(self):
self.ns = {}
def __getitem__(self, key):
return self.ns[key][-1] # Rule 1. We return last value in history
def __delitem__(self, key):
self.ns[key].append(None) # Rule 4. Instead of delete we will insert None in history
def __setitem__(self, key, value): # Rule 3. Instead of update we insert value in history
if key in self.ns:
self.ns[key].append(value)
else:
self.ns[key] = list([value,]) # Rule 2. Instead of insert we create history list
def __len__(self):
return len(self.ns)
def __iter__(self):
return iter(self.ns)
history_locals = HistoryNamespace()
exec('''
foo=2
foo=3
del foo
foo=4
print(foo)
''', {}, history_locals)
print("History of foo:", history_locals.ns['foo'])
import sys
class LocalsTracer:
"""Tracer for local assignment that prints the history of names"""
def __init__(self, frame, event, arg):
assert event == "call"
# identifier for the call we are tracing - name, file, line
self.subject = "%s (%s:%s)" % (frame.f_code.co_name, frame.f_code.co_filename, frame.f_code.co_firstlineno)
self.names = {}
# tracer gets *called* by the interpreter
def __call__(self, frame, event, arg):
if event == "line":
self.trace_names(frame, event, arg)
elif event in ("return", "exception"):
self.trace_names(frame, event, arg)
self.trace_exit(frame, event, arg)
else:
raise RuntimeError("Invalid event: %r" % event)
def trace_names(self, frame, event, arg):
"""Capture modifications of names and store their history"""
for name, value in frame.f_locals.items():
try:
if self.names[name][-1] != value:
self.names[name].append(value)
except KeyError:
self.names[name] = [value]
return self
def trace_exit(self, frame, event, arg):
"""Report the current trace on exit"""
print("exit", self.subject, "via", event)
print(self.names)
# trace targets can be defined regularly, anywhere
def bar(b): # tracer captures function parameters
b = 4
def foo():
a = 1
b = 2
bar(27) # tracer can recurse
a = 3
sys.settrace(LocalsTracer) # start tracing locals assignment
foo()
sys.settrace(None) # stop tracing
否。如果不给对象分配另一个变量,就无法知道变量的前一个值。只有引用的存在才能使对象在内存中保持活动状态。当对象的引用计数达到零时,垃圾回收器将处理该对象。在
但是,根据Fluent Python by Luciano Ramalho中的示例,在控制台会话中可能使用对对象的弱引用(弱引用不会增加对象的引用计数!)公司名称:
VS
^{pr2}$输出:
技巧是Python控制台自动将变量
_
分配给表达式的结果,而表达式不是None
回答:实际上,我们可以
但不是一般情况。在
你需要一些魔法。在
magick被称为“自定义名称空间”。在
整个想法来自阿明·罗纳彻的演讲5 years of Bad Ideas。在
Magick:具有值历史记录的自定义命名空间
让我们创建保存值历史记录的自定义命名空间。在
为了演示起见,让我们更改
__del__
的规则,而不是删除值,而是插入None。在高兴吧!在
自定义名称空间是非常强大的技术,但几乎从未使用过。在
我觉得这个事实有点令人费解。在
简短回答否,长回答是,如果你自己做的话。在
否
local names的精确处理(dict,array,…)是由实现定义的,但是对于所有的意图和目的,都不会跟踪名称的历史记录。没有一个主要的实现提供这种功能。在
就Python语言而言,没有指定名称的对象已经不存在了。实际上,垃圾回收可以自由声明任何当前未绑定到名称的环境对象。无论是immediately还是at an arbitrary time都不会改变这样的对象是Python代码的禁区。否则,Python将不得不保留大量死掉的对象。在
一旦名称被重新命名,它以前的引用对象就会从中消失。
是的,但请不要这样做,除非您真的需要
有多种方法可以钩住Python代码的执行。例如,可以使用^{} 截获调用/行/返回;调试器就是这样工作的,可以检查任何内容。如果您可以控制实际代码的执行方式,请参见Alex Yu's answer以获取仅钩住命名空间的方法。在
相关问题 更多 >
编程相关推荐