pythonclassoopinstanceclass-attributes

Why did my output change when I called the class attribute from an instance instead of the class?


(I'm fairly new to programming, so understand that my query might not make sense. I've tried my best to explain it but if you are still confused, you can ask me to clarify)

I understand the that we can call the class attribute number_of_people and increment by one so that when we create a new instance (in this context, a person), the number of people increases by one:

class Person:

     # Class attribute
     number_of_people = 0

     # Constructor
     def __init__(self, name):
        self.name = name
        # Every time we call the constructor, we increment the number of people.
        Person.number_of_people += 1

# Driver code
p1 = Person("Jack")
print(Person.number_of_people)
# output gives 1

However, I'm having trouble with understanding the output of the code when we change the we choose to increment p1.number_of_people instead of Person.numer_of_people:

class Person:

     # Class attribute
     number_of_people = 0

     # Constructor
     def __init__(self, name):
        self.name = name
        # Every time we call the constructor, we increment the number of people.
        p1.number_of_people += 1

# Driver code
p1 = Person("Jack")
print(p1.number_of_people)
# output gives 0 (I expected the output to be 1)

I thought that since class attributes can be accessed by both the class and instances, my change wouldn't make a difference. I suspect it has to do with p1 being mentioned in the class before it's mentioned in the driver code, but I'm not sure where to go from there.


Solution

  • I suspect the demonstration you were trying to do for yourself is to examine the difference between using the class attribute as a class attribute, vs as an instance attribute. Consider this difference:

    class Person:
        population = 0
    
        def __init__(self,name):
            self.name = name
            Person.population += 1
    
    p1 = Person("Jack")
    p2 = Person("Tom")
    p3 = Person("Bill")
    print(p1.population)
    print(p2.population)
    print(p3.population)
    

    Output:

    3
    3
    3
    

    Compared to:

    class Person:
        population = 0
    
        def __init__(self,name):
            self.name = name
            self.population += 1
    
    p1 = Person("Jack")
    p2 = Person("Tom")
    p3 = Person("Bill")
    print(p1.population)
    print(p2.population)
    print(p3.population)
    

    Output:

    1
    1
    1
    

    In the second example, the instance starts out using the class attribute, but as soon we change it, it creates an instance attribute that has a separate life.