在Python中查找变量的先前值

时间:2019-02-18 09:13:21

标签: python

这可能是一个非常奇怪的问题,但是

考虑一个名为 a 的变量。 现在让我们为其分配一个值,如下所示:

a = 1

让我们现在更改 a 的值。

a = 3

Python中是否有任何方法可以知道变量的先前值而不将其存储在另一个变量中.python是否在内部维护了变量在其生命周期中可以访问的所有值的分类帐? >

3 个答案:

答案 0 :(得分:9)

答案:实际上,我们可以

但一般情况下不行。

为此您需要一些魔术。

magick被称为“自定义名称空间”。

整个想法来自Armin Ronacher的演讲5 years of Bad Ideas

Magick:具有值历史记录的自定义命名空间

让我们创建保存值历史记录的自定义命名空间。

出于演示目的,让我们更改__del__的规则-我们将插入“无”,而不是删除值。

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'])

高兴!

自定义名称空间是一种非常强大的技术,但几乎从未使用过。

我觉得有些困惑。

答案 1 :(得分:4)

简短答案,长答案是的,如果您自己做


local names的精确处理(字典,数组等)是由实现定义的,但是出于所有意图和目的,都不会跟踪名称的历史记录。没有主要的实现提供此功能。

就Python语言而言,没有分配给名称的对象已消失。实际上,垃圾回收可以自由声明当前未绑定到名称的任何环境对象。无论是immediately还是at an arbitrary time,都不会改变此类对象对Python代码的限制。否则,Python将不得不大量保留死对象。

重新分配名称后,该名称的前一个引用对象也将消失。


是的,但是除非您确实需要

,否则请不要这样做

可以通过多种方式来执行Python代码。例如,您可以使用sys.settrace拦截呼叫/线路/回车;这就是调试器的工作方式,可以检查任何东西。如果您可以控制实际代码的执行方式,请参见Alex Yu's answer,以了解一种仅挂接到名称空间的方法。

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

答案 2 :(得分:0)

。如果不给对象分配另一个变量,就无法知道变量的先前值。只有引用的存在才能使对象在内存中保持活动状态。当对象的引用计数达到零时,垃圾收集器将处理该对象。

但是,根据Fluent Python by Luciano Ramalho中的示例,有可能在控制台会话中使用对对象的弱引用(弱引用不会增加对象的引用计数!):

var city = {shortName : 'NY', fullName : 'New York'}:

VS

var abc = { NY : 'New York'};

输出:

 static JSONObject messageToJSON()
 {
 JSONObject requestJson = new JSONObject();
 JSONObject meta= new JSONObject();
 JSONObject payload= new JSONObject();
 JSONArray arrayJson = new JSONArray();
 String messageData="My Message";    
 try
 {
 requestJson.put("message", messageData);
 requestJson.put("messageType", "html");
 payload.put("title",  "Thanks");
 payload.put("message",  "Thank you");
 arrayJson.put(payload);
 meta.put("contentType", "300");
 meta.put("templateId", "6");
 meta.put("contentType", "300");
 meta.put("payload", arrayJson);
 requestJson.put("metadata", meta);
 System.out.println(requestJson.toString());
 }
 catch (JSONException e)
 {
 e.printStackTrace();
 }
 return requestJson;
 }

诀窍是Python控制台会自动将变量 static JSONObject messageToJSON() { JSONObject requestJson = new JSONObject(); JSONObject meta= new JSONObject(); JSONObject payload= new JSONObject(); JSONArray arrayJson = new JSONArray(); String messageData="My Message"; try { requestJson.put("message", messageData); requestJson.put("messageType", "html"); meta.put("contentType", "300"); meta.put("templateId", "6"); meta.put("contentType", "300"); requestJson.put("metadata", meta); System.out.println(requestJson.toString()); } catch (JSONException e) { e.printStackTrace(); } return requestJson; } 分配给表达式的结果,而不是>>> import weakref >>> a = {0, 1} >>> wref = weakref.ref(a) >>> wref() {0, 1} >>> a = {2, 3} >>> wref() {0, 1}