Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python object containing an array of objects being weird [duplicate]

Possible Duplicate:
Static class variables in Python
Python OOP and lists

just wondering if I could get some help on this.

I am using python, and have hit an obstacle that I can't seem to figure out with a small program I am working on. Here is my problem (using a very simple and unrelated example): I have a class:

class dog:
    name = ''
    friends = []

I make a couple objects from it:

fido = dog()
rex = dog()

And here is where I get stuck. I don't know why this is happening and I haven't figured it out. I'm assuming my understanding of something is deficient though, any explanation would be great. So here is my problem, if I append one object to the other (which seems like it should work just fine):

fido.friends.append(rex)

... things mess up. As you can see here:

>>> fido.friends.append(rex)
>>> fido.friends
[<__main__.dog instance at 0x0241BAA8>]
>>> rex.friends
[<__main__.dog instance at 0x0241BAA8>]
>>> 

That just deosn't make sense to me. Shouldn't only fido.friends have something in it? Even if I make a new object:

rover = dog()

It has a dog instance in it, which we can see is our 'rex' object.

>>> rex.name = "rex"
>>> fido.friends[0].name
'rex'
>>> rex.friends[0].name
'rex'
>>> rover.friends[0].name
'rex'
>>> 

This just isn't making sense, and I'd love some help. I searched around for awhile trying to find an explanation, but didn't. Sorry if there is a similar question I missed.

like image 716
A'nW Avatar asked Jan 06 '13 01:01

A'nW


4 Answers

If each dog should have his own list of friends, you must use instance attributes:

class Dog(object):

    family = 'Canidae' # use class attributes for things all instances share 

    def __init__(self, name):
        """ constructor, called when a new dog is instantiated """
        self.name = name
        self.friends = []

    def __repr__(self):
        return '<Dog %s, friends: %s>' % (self.name, self.friends)

fido = Dog('fido')
rex = Dog('rex')

fido.friends.append(rex)
print(fido) # <Dog fido, friends: [<Dog rex, friends: []>]>

What you used were class attributes (the value is shared among instances). More on this:

  • http://www.diveintopython.net/object_oriented_framework/class_attributes.html
like image 132
miku Avatar answered Nov 02 '22 18:11

miku


Variables declared inside of the class, not attached to an instance, are static variables in python.

like image 28
dm03514 Avatar answered Nov 02 '22 18:11

dm03514


To avoid this, put your variable declaration within a __init__ function, like so:

class Dog:
    def __init__(self):
        self.name = ''
        self.friends = []
like image 1
Volatility Avatar answered Nov 02 '22 19:11

Volatility


the proper way to achieve what you want to do is the use of the __init__ method:

>>> class dog:
       def __init__(self):
           self.f = []


>>> a = dog()
>>> b = dog()
>>> a.f.append(b)
>>> a.f
[<__main__.dog instance at 0x02DA6F08>]
>>> c = dog()
>>> c.f
[]
like image 1
Samuele Mattiuzzo Avatar answered Nov 02 '22 19:11

Samuele Mattiuzzo