更改类中的变量

时间:2011-04-16 20:14:12

标签: python variables

我正在编写游戏的文本字段类。 它应该从类外部将字符串更改为用户输入的字符串。 以下是伪代码,但您应该了解我的问题:D

class txtfield(pygame.sprite.Sprite):
    def __init__(self, var, name, x, y):
        self.var=var
        self.value=""  


    def update(self, key):
        #I removed image-changing and the code which changes the string self.value 
        #key is a character from the last pressed button
        #(self.value+=key)
        if key=="return":
            self.var=self.value
            # I want this to be like 'a=self.value'.
            #-> assuming self.name is 'Peter', 'a' should change to 'Peter' 
            #if the user hits enter

a="NAME"
txt=txtfield(a, "popo", 20, 20)

我只是希望txtfield更改变量a,但显然这与我的工作方式不同。

3 个答案:

答案 0 :(得分:5)

你做不到。 Python只是按值传递,你要求传递引用。使用它构建的所有内容来解释完整的模型将是冗长的并且已经在官方文档中完成(阅读:如果你想要更多细节请参考),但是长话短说,你的代码中会发生什么:

  • a被赋予一个指针/引用(与“pass-by-reference”中的“引用”不同!)到一个字符串对象("NAME"
  • 调用类的构造函数时,会复制指针/引用(按值传递)。
  • 此引用再次复制到self
  • 字段中

您会看到,self字段中存储的引用与a中存储的引用完全无关。它们指的是同一个对象,但它们是完全独立的副本。 使用新引用覆盖一个(这就是你所能做的)不会改变其他副本。当然不是,怎么可能呢?

现在,对可变对象的引用将是另一回事。您仍然无法更改其他范围内的引用,但显然可以更改其他人在查看引用副本时看到的内容(例如更改字段)。字符串是不可变的,所以这对你没有帮助。一般情况下模拟传递引用(您必须通过代理对象的字段路由所有)但仅共享状态是没有用的。因此,最简单的解决方案是:问问自己为什么需要这样做,并提出更清洁/更可行的解决方案。

答案 1 :(得分:0)

看起来你真正想要的是一个回调:

class txtfield(pygame.sprite.Sprite):
    def __init__(self, ***callback***, name, x, y):
        ***self.callback=callback***
        self.value=""

    def update(self, key):
        #I removed image-changing and the code which changes the string self.value 
        #key is a character from the last pressed button
        #(self.value+=key)
        if key=="return":
            ***self.callback(self.value)***
            # I want this to be like 'a=self.value'.
            #-> assuming self.name is 'Peter', 'a' should change to 'Peter' 
            #if the user hits enter

***def myCallback(text):
    print(text)***
txt=txtfield(***myCallback***, "popo", 20, 20)

您甚至可以这样设置变量:

class MyController(object):
    def __init__(self):
        self.A = ''

    def makeCallback(self):
        """
            Makes a callback which modifies self.A
        """
        def myCallback(text):
            self.A = text
        return myCallback

controller = MyController()
txt = txtfield(controller.makeCallback(), "popo", 20, 20)
assert controller.A=='popo'  #--> True!

您无法在原始版本中“设置变量”的原因是因为您告诉函数“set'popo'为'popo'”;函数设置需要知道对象名称的东西。在我上面给出的例子中,你说的是“将self.A设置为'popo'”。这是一个没有类的例子:

A = ''
def setA(text):
    A = text
txt = txtfield(setA, "popo", 20, 20)
assert A=='popo'

以下是使用词典(您也可以使用列表)以避免必须提供卡片编码名称的示例:

lookupTable = {}
def setA(text):
    lookupTable['A'] = text
txt = txtfield(setA, "popo", 20, 20)
assert lookupTable['A']=='popo'

答案 2 :(得分:0)

正如德尔南的帖子所示,如果您更多地了解您的目标,我们可以提供更好的帮助。也就是说,我认为做你想要的最好的方法是将要修改的变量封装在一个类中,然后使用setattr

class UserEnteredData(object):
    def __init__(self):
        self.a = None
        self.b = None

class TextField(pygame.sprite.Sprite):
    def __init__(self, userdata, uservar, name, x, y):
        self.userdata = userdata
        self.var = uservar
        self.value = ""  
    def update(self, key):
        if key == "return":
            setattr(self.userdata, self.var, self.value)

userdata = UserEnteredData
userdata.a = "NAME"
txt = TextField(userdata, "a", "popo", 20, 20)
txt.update("return")
print userdata.a       # prints a null string

你也可以使用字典,正如ninjagecko在答案结束时建议的那样,但我认为这更接近你想要的东西。

但是,我怀疑你应该想要别的东西。如果可能的话,一个更好的解决方案就是让update 返回一个值,如:

class TextField(pygame.sprite.Sprite):
    # [... define init here ...]
    def update(self, key):
        if key=="return":
            return self.value

# [... create txt, etc ...]
a = txt.update("return")