Изменение переменной внутри класса - PullRequest
1 голос
/ 17 апреля 2011

Я программирую класс текстового поля для игры. Предполагается изменить строку вне класса на строку, которую вводит пользователь. Ниже приведен псевдокод, но вы должны понять мою проблему: 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 ]

5 голосов
/ 17 апреля 2011

Вы не можете.Python является исключительно передачей по значению, вы запрашиваете передачу по ссылке.Объяснение полной модели со всем, на чем она построена и т. Д., Было бы длинным и уже было сделано в официальной документации (читай: обратитесь к этому, если вы хотите больше подробностей), но вкратце, что происходит в вашем коде так:

  • a назначается указатель / ссылка (не та же «ссылка», как в «передаче по ссылке»!) На строковый объект ("NAME")
  • , которыйуказатель / ссылка копируется (передача по значению) при вызове конструктора класса.
  • Эта ссылка снова копируется в поле self.

Видите ли,ссылка, хранящаяся в поле self, совершенно не связана с той, которая хранится в a.Они ссылаются на один и тот же объект, но являются полностью независимыми копиями. Перезапись одна с новой ссылкой (это все, что вы можете сделать) не изменит другие копии.Конечно нет, как это могло быть?

Теперь ссылки на изменяемый объект - это другое дело.Вы по-прежнему не можете изменить ссылки в другой области, но вы, очевидно, можете изменить то, что видят другие, когда они следуют за своей копией ссылки (например, изменяют поля).Строки, тем не менее, неизменны, так что это вам не поможет.И вообще бесполезно эмулировать передачу по ссылке (вам нужно будет направить все через поле прокси-объекта), но только для совместного использования состояния.Итак, самое простое решение: спросите себя, какого черта вам это понадобится, и придумайте более чистое / более выполнимое решение.

0 голосов
/ 17 апреля 2011

Как указывает пост Делнана, мы могли бы оказать вам лучшую помощь, если бы вы сказали больше о том, какова ваша цель.Тем не менее, я думаю, что лучший способ сделать то, что вы говорите, что вы хотите, это инкапсулировать переменные, которые будут изменены в классе, и использовать 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")
0 голосов
/ 17 апреля 2011

Похоже, что вы на самом деле хотите обратного вызова:

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!

Причина, по которой вы не могли «установить переменную» в исходной версии, заключалась в том, что вы сказали функции «установить« 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'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...