Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird Python behaviour - or am I missing something

Tags:

python

oop

The following code:

class House:
    links = []

class Link:
    pass

class Villa(House):
    pass

if __name__ == '__main__':
    house = House()
    villa = Villa()
    link = Link()
    house.links.append(link)

    print house.links
    print villa.links

results in this output:

[<__main__.Link instance at 0xb65a4b0c>] 
[<__main__.Link instance at 0xb65a4b0c>]

I find this very weird: Since it is another instance? - I would have expected that the output is - Since it is another instance?:

[<__main__.Link instance at 0xb65a4b0c>] 
[]

When changing the line house.links.append(link) to house.links = [link] everything works as expected.

Can somebody explain this behavior?

like image 320
user389821 Avatar asked Nov 29 '22 05:11

user389821


2 Answers

It is another instance, but you have defined links as a class variable rather than an instance variable.

An instance variable would be defined as such:

class House(object):  # Always use new-style classes except for backward compatibility
  def __init__(self):
    self.links = []

Note that in Python, unlike other languages, an instance variable is explicitly declared to be a property of an instance. This usually happens in the __init__ method, to ensure that every instance has the variable.

Then, the subclass would look like this:

class Villa(House):
  def __init__(self):
    super(Villa, self).__init__()

And executing your code gives the correct results:

>>> house = House()
>>> villa = Villa()
>>> link = Link()
>>> house.links.append(link)
>>> print house.links
[<__main__.Link instance at 0xcbaa8>]
>>> print villa.links
[]
like image 170
danben Avatar answered Dec 30 '22 14:12

danben


In your code, links is an attribute on the class, making it shared by all instances of that class:

class House:
    links = []

Because of this, your Villa class shares this attribute, because an instance of Villa is (as a subclass) also an instance of House.

If you want to make links an instance variable, write a constructor and set links as an attribute of self, e.g.

class House:
    def __init__(self):
        self.links = []
like image 45
Eli Courtwright Avatar answered Dec 30 '22 14:12

Eli Courtwright