在Python中,我可以将变量绑定到函数/表达式,以便它自动更新吗?

时间:2012-04-22 07:12:02

标签: python

假设我有一个变量A,它是函数/表达式F的结果。反过来,F中有许多其他变量,比方说X,Y和Z.

是否可以将A绑定到F,以便每当X,Y或Z发生变化时,A会自动更新?

我想要避免的是每次X,Y和Z发生变化时,我都要记得在代码中明确更新A.我也不想每次想要使用A来调用该函数。

示例(根据要求):我有以下功能:

def calcHits():
    return sum(hitDiceRolls,level*modList['con']) 

在我的程序中(函数之外),我有一个名为hitPoints的变量(是的,它是一个角色扮演游戏程序)。每当函数中使用的变量发生变化时,我都希望hitPoints也能改变。

2 个答案:

答案 0 :(得分:4)

在Python中执行此操作的典型方法是使用class

class ExpressionBinder:
    def __init__(self, f):
        self.f = f
        self.x = 0
        self.y = 0
        self.z = 0

    @property
    def result(self):
        return self.f(self.x, self.y, self.z)

你可以像这样使用它:

def f(x, y, z):
    return x**3 + y**2 + z

b = ExpressionBinder(f)
b.x = 1
b.y = 2
b.z = 3
print(b.result)

答案 1 :(得分:2)

Python无法在全局或本地范围内自动重新绑定名称以响应其他名称被反弹。但是,应该可以创建一个可以跟踪某些值的类,并且有一个成员函数可以返回您调用的值A。并且,正如@Alok所指出的,您可以使用属性描述符来创建一个隐式调用函数以返回其值的成员名称,这样您就可以隐藏该函数并将该名称视为普通的旧名称。

class Trk(object):
    """Track some values and compute a function if any change"""
    def __init__(self, name, fn, **objects_to_track):
        def _trk_fn(self):
            if any(self.__dict__[x] != self.original_objects[x] for x in self.original_objects):
                self.value = self.saved_fn(self.__dict___)
                # now that self.value is updated, also update self.original_objects
                for x in self.original_objects:
                    self.original_objects[x] = self.__dict__[x]
            return self.value

        self.original_objects = objects_to_track  # make reference copy
        self.__dict__.update(objects_to_track)
        self.name = name
        self.saved_fn = fn
        self.fn = self._trk_fn()
        self.value = self.fn()

我很抱歉,但我现在很累,而且我完成了这个例子。我也没有测试过。但这显示了一种跟踪价值观的方法,如果它们不同,则做一些不同的事情。你这样使用它:

# want to track x, y, z
trk = Trk(x, y, z)
trk.fn() # returns up-to-date value

trk.x = new_value
trk.fn() #detects that trk.x changed and computes new trk.value

如果上述方法有效,您可以使用属性描述符来绑定名称,以便尝试从名称中读取值将调用self.fn()

编辑:哦,重要的是,self.value更新后,self.original_objects应该更新。我添加了代码来做到这一点。

现在我要睡觉了!