Joel Hoelting
Joel Hoelting

Reputation: 1992

Python: calling class variables and class methods from within __init__ function

I am trying to gain a better understanding of class variables and the @classmethod decorator in python. I've done a lot of googling but I am having difficulty grasping basic OOP concepts. Take the following class:

class Repository:
    repositories = []
    repository_count = 0

    def __init__(self):
        self.update_repositories()
        Repository.repository_count += 1

    @classmethod
    def update_repositories(cls):
        if not cls.repositories:
            print('appending repository')
            cls.repositories.append('twenty')
        else:
            print('list is full')


a = Repository()
b = Repository()
print(Repository.repository_count)

Output:

appending repository
list is full
2
  1. In the __init__ method, why does self.update_repositories() successfully call the update_repositories class method? I thought that self in this case refers to the instantiated object, not the class?

  2. The code works without using the @classmethod decorator. Why?

  3. In the __init__ method why do I need to use the keyword Repository in Repository.repository_count += 1? Am I doing this correctly or is there a better practice?

Upvotes: 0

Views: 72

Answers (1)

sarartur
sarartur

Reputation: 1228

  1. Class methods can be called from an instance. Look at the documentation here.

A class method can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class. If a class method is called for a derived class, the derived class object is passed as the implied first argument.

  1. The function works without the decorator, but it is not a class method. The cls and self parameter names are simply convention. You can put anything in the place of cls or self. For example:

    class Demo:
    
        def __init__(self):
            pass
    
        def instance_method(test):
            print(test)
    
        @classmethod
        def class_method(test):
            print(test)
    
    demo = Demo()
    

    This results in:

    demo.instance_method()
    >>> <__main__.Demo object at 0x7facd8e34510>
    
    demo.class_method()
    >>> <class '__main__.Demo'>
    

    So all non decorated methods in a class are a considered instance methods and all methods decorated with @classmethod are class methods. Naming your parameters cls, self or anything else for that matter does not effect the functionality, but I would strongly advice sticking with convention.

    In your case specifcally removing the @classmethod decorator turns the method into an instance method and cls is now actually what self would normally be, a reference to the class's instance. Since class methods and attributes can be called from an instance cls.update_repositories still points to the class variable.

  2. Depends on what you are trying to do. Generally if you want to access a class variable or method inside a class, but outside a class method, your approach is correct.

Upvotes: 1

Related Questions