0

I'm writing a tic-tac-toe game in Python and for one part I have a lot of instance variables in a class and they are all inside a list. I'm trying to change one the instance variables, but when it is inside the list, I can only change the list element.

Here some code:

# only a piece of my code

class Board(object):
    def __init__(self):
        self.one = "1"
        self.two = "2"
        self.three = "3"

board = Board()

configs = [board.one, board.two, board.three]
configs[2] = "X"
print board.three
print configs

Expected result:

X
['1', '2', 'X']

Actual result:

3
['1', '2', 'X']

Is there the a way to get my expected result?

2 Answers 2

1

Have you thought about using better data structures? Like dictionaries i.e.

class Board(object):
    def __init__(self):
        self.dict = {"one":"1", "two":"2", "three":"3"}

And then you could do something like:

>>> a = Board()
>>> a.dict
{'three': '3', 'two': '2', 'one': '1'}
>>> for element in a.dict:
    a.dict[element] = element+"x"
>>> a.dict
{'three': 'threex', 'two': 'twox', 'one': 'onex'}
>>> a.dict["one"] = "1"
>>> a.dict
{'three': 'threex', 'two': 'twox', 'one': '1'}

The solution you're looking for is also possible (most likely with some very very weird getattrs etc... and I wouldn't really recommend it.

Edit1 It turns out (after checking) that your class attributes will be stored in a object.__dict__ anyhow. SO why not use your own.

Just also to clarify it is possible emulating container objects with your own class by defining __getitem__ and __setitem__ methods like bellow:

class Board(object):
    def __init__(self):
        self.dict = {"one":"1", "two":"2", "three":"3"}
    def __getitem__(self,key):
        return self.dict[key]
    def __setitem__(self, key, value):
        self.dict[key] = value

Which means you don't have to keep writing a.dict everywhere and can pretend your class is the container (dict) like bellow:

>>> a = Board()
>>> a.dict
{'three': '3', 'two': '2', 'one': '1'}
>>> a["one"]
'1'
>>> a["one"] = "x"
>>> a.dict
{'three': '3', 'two': '2', 'one': 'x'}
Sign up to request clarification or add additional context in comments.

Comments

1

Strings are immutable objects, so when you change the item in the list with the given index, list now points to totally separate string X.

Same scenario applies here;

>>> configs[2] += "X"
>>> print configs[2]
'3X'

>>> print board.three
'3'

One alternative would be to execute a callback function whenever an item in the list gets updated. (However, I'd personally discourage that, because it seems an hacky solution.)

class interactive_list(list):
    def __init__(self, *args, **kwargs):
        self.callback = kwargs.pop('callback', None)
        super(interactive_list, self).__init__(*args, **kwargs)

    def __setitem__(self, index, value):
        super(interactive_list, self).__setitem__(index, value)
        if self.callback:
            self.callback(index, value)

>>> board = Board()

>>> def my_callback(index, value):
...    if index == 2:
...        board.three = value

>>> configs = interactive_list([board.one, board.two, board.three], callback=my_callback)
>>> configs[2] = 'X'

>>> print board.three
'X'

2 Comments

It is not a problem, it is totally expected. You need to change your logic. You might considering storing configs list in your class.
Why store the values in a list at all? Just modify the property directly if that's what you want to do!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.