在Python中监视变量访问和对象创建

在Python中监视变量访问和对象创建,python,Python,我在玩弄这个想法,主要是在理论上,在游戏中实现时间旅行。我提出的实现非常简单: 在Python程序模拟的游戏世界中发生的一切最终归结为一个操作:一个变量被改变 因此,可以通过记录每个变量的变化来实现时间旅行;具体来说,存储更改前的值以及更改发生的时间。当时间应该反转时,程序将在事件列表上迭代,直到到达时间戳在目标时间之前的事件。它也可以在时间上向前移动,假设它已经向后移动,方法是在最初发生的时间执行操作列表中的操作 当然,这其中的关键部分是一种在变量改变时做出反应的方法。如果我理解正确的话,我想

我在玩弄这个想法,主要是在理论上,在游戏中实现时间旅行。我提出的实现非常简单:

在Python程序模拟的游戏世界中发生的一切最终归结为一个操作:一个变量被改变

因此,可以通过记录每个变量的变化来实现时间旅行;具体来说,存储更改前的值以及更改发生的时间。当时间应该反转时,程序将在事件列表上迭代,直到到达时间戳在目标时间之前的事件。它也可以在时间上向前移动,假设它已经向后移动,方法是在最初发生的时间执行操作列表中的操作


当然,这其中的关键部分是一种在变量改变时做出反应的方法。如果我理解正确的话,我想用描述符可以做到这一点,但那会很烦人。我更喜欢有一种方法让时间旅行“选择退出”;也就是说,程序会记录任何变量的变化,但没有明确告诉它不要这样做。有没有一种方法可以在Python中实现这一点(无论如何都不必让自己成为自定义解释器)?

当然,Python有一些神奇的方法:。。。其中一个是
\uuuuu setattr\uuuuuuu(自我、名称、值)

它允许您定义属性赋值的行为 无论该属性是否存在,这意味着您可以 为属性值中的任何更改定义自定义规则

您可以创建一个“时间旅行”基类,该基类覆盖
\uuuu setattr\uuuu
,在该基类中,您可以记录时间旅行子类中分配给任何属性的时间和值

更新——这里有一个具体的例子,其中
Gun
TimeTravelBase
类进行了子类化<代码>枪的
颜色
属性将从其历史记录中选择,而分配给
发射的炮
的新值以及分配时间将附加到
的历史记录中:

import time

class TimeTravelBase(object):
    def __init__(self):
        self.history = []
        self.blacklist = ['blacklist']

    def __setattr__(self, name, value):
        super(TimeTravelBase, self).__setattr__(name, value)
        if hasattr(self, 'blacklist') and name not in self.blacklist:
            self.history.append({'time': time.time(), 'name': name, 'value': value})

class Gun(TimeTravelBase):
    def __init__(self):
        super(Gun, self).__init__()
        self.blacklist.append('color')
        self.shots_fired = 0
        self.color = "black"

    def fire(self):
        self.shots_fired += 1

if __name__=='__main__':
    gun = Gun()
    gun.color = "red"
    gun.fire()
    from pprint import pprint
    pprint(gun.history)
输出:

[{'name': 'shots_fired', 'time': 1386281320.322638, 'value': 0},
 {'name': 'shots_fired', 'time': 1386281320.322645, 'value': 1}]

“任何Python程序中发生的一切”都不能简化为变量赋值。即使忽略了外部可见的副作用,调用堆栈的状态也不能用赋值来记录。这个想法让我想起了事务或模式。游戏状态只能通过向其显示一个命令对象来修改,该命令对象的属性完全描述了提议的修改。这使得实现撤销、重做、延迟执行等变得容易。我强烈建议不要尝试反转解释器状态。将解释器状态反转以实现时间旅行,就像将物理对象粉碎在一起以实现物理引擎一样必要。不过,将时间旅行作为游戏基础的想法充满了潜力。退房它有我见过的最好的时间旅行系统,尽管游戏的其他部分没有那么好。@user2357112我不确定我是否理解;为什么我关心调用堆栈的状态?记住,我说的不是程序本身意义上的时间反转,而是程序模拟的世界中的时间反转。我将编辑这个问题来澄清这一点。啊,setattr将是实现这一点的更简单的方法。尽管如此,它仍然是选择加入的,而我更希望这个系统是选择退出的。可以更改对象吗?\uuuu setattr\uuuuuuuuo?@Schilcote:是的,只需实现您自己的
\uuuuuu setattr\uuuuuuuuuu
-方法,执行日志记录或任何需要的操作,最后调用
超级(YourClass,self)。\uuuuu setattr\uuuuuuuuuuo(self,name,value)
即可为其业务逻辑执行父/超级方法。唉,事实证明,所描述的设计没有考虑可变项;一个完全不使用它们而设计的游戏可能会奏效。不过,答案不错,我很惊讶我自己没有想到P