I have defined a class Listener
and created a dictionary of Listener
objects. Each listener has an id
to identify them, and a list of artists
they listen to, artists = []
. Adding something to the artists
list adds it for all instances of the Listener
class, rather than the referred instance. This is my problem.
The Listener class is defined as follows:
class Listener:
id = ""
artists = []
def __init__(self, id):
self.id = id
def addArtist(self, artist, plays):
print self.id # debugging...
print "pre: ", self.artists
self.artists.append(artist)
print "post: ", self.artists
Here is my debugging test code:
def debug():
listeners = {}
listeners["0"] = Listener("0")
listeners["1"] = Listener("1")
listeners["0"].addArtist("The Beatles", 10)
listeners["0"].addArtist("Lady Gaga", 4)
listeners["1"].addArtist("Ace of Base", 5)
And the output:
0
pre: []
post: ['The Beatles']
0
pre: ['The Beatles']
post: ['The Beatles', 'Lady Gaga']
1
pre: ['The Beatles', 'Lady Gaga']
post: ['The Beatles', 'Lady Gaga', 'Ace of Base']
My expected output is that the final addArtist("Ace of Base", 5)
call would result in the output
1
pre: []
post: ['Ace of Base']
Is this a subtlety of Python I'm not understanding? Why is this the output and how can I get the desired output instead? Thanks!
Method 1: To get the list of all the attributes, methods along with some inherited magic methods of a class, we use a built-in called dir() . Method 2: Another way of finding a list of attributes is by using the module inspect .
A Python class variable is shared by all object instances of a class. Class variables are declared when a class is being constructed. They are not defined inside any methods of a class. Because a class variable is shared by instances of a class, the Python class owns the variable.
list is a built-in class in Python. However, classes are callable just like functions, and when called, classes instantiate and return objects, so you can pass a class as an argument where a function (or a callable to be precise) is expected.
We can create list of object in Python by appending class instances to list. By this, every index in the list can point to instance attributes and methods of the class and can access them. If you observe it closely, a list of objects behaves like an array of structures in C.
You don't want the members declared inside the class, but just set in the __init__
method:
class Listener:
def __init__(self, id):
self.id = id
self.artists = []
def addArtist(self, artist, plays):
print self.id # debugging...
print "pre: ", self.artists
self.artists.append(artist)
print "post: ", self.artists
If you have a class like
class A:
x=5
Then x is a member of the class and not a member of instances of that class. This can be confusing, since python lets you access class members through the instance:
>>> a=A()
>>> print a.x
5
But you can also access it through the class itself:
>>> print A.x
5
It would even appear that this works properly:
>>> a1=A()
>>> a2=A()
>>> a1.x=6
>>> print a1.x
6
>>> print a2.x
5
but what has actually happened is that you've put a new x into the a1 instance, which will be printed instead of the class member, which still has its original value:
>>> print A.x
5
You only start to see a difference when you have something that can be changed, like a list:
class A:
l=[]
>>> a1=A()
>>> print a1.l
[]
>>> a2=A()
>>> print a2.l
[]
>>> a1.l.append(5)
>>> print a1.l
[5]
>>> print a2.l
[5]
>>> print A.l
[5]
Is this a subtlety of Python I'm not understanding?
It's not subtle, it's quite simple; unlike in other languages which confuse the issue, in Python everything you declare inside the class belongs to the class. This is natural, since classes are objects (like everything else), and thus a perfectly valid place to attach things. Thus, all those methods belong to the class (instead of being somehow magically copied to each instance), and so do the data attributes.
Each listener has an
id
to identify them
Yes, because you attach one to each instance in the __init__
. This has nothing to do with the id
that belongs to the class - except that when you look up id
via an instance, the instance's own id
will be found, hiding the one belonging to the class.
and a list of artists they listen to, artists = []
When you look up artists
via the class, however, the class' artists
will be found, because the instance doesn't have one.
Adding something to the artists list adds it for all instances of the Listener class
No; it's added to the class itself, which is where things are looked for when they aren't found in the instance.
Keep in mind that if you made a direct assignment like self.artists = []
on an instance later, that instance would get its own list hiding the class' list. Other instances would not, because that code didn't get run on the other instances.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With