The built-in classmethod function, is a decorator function that allows a method to be bound to a class rather than an instance. It is used to define a method that can be invoked directly without necessarily creating an instance of the class. This allows you to access and modify class-specific attributes and perform operations that are relevant to the entire class.

Syntax:

@classmethod
def func(cls, arguments):
    #body

            or 

def func(cls, arguments):
    #body

TargetClass.some_method = classmethod(func)
copy

Instance methods are meant to be used by objects and not by the class itself.  By convention, instance methods have self as the first parameter, which refers to the instance calling the method while class methods have cls as the first parameter.

ExampleEdit & Run
class Myclass():
    def __init__(self):
        self.name = 'class instance'
    def example_method(self):
        print('Hello, World!')

myInstance= Myclass()

myInstance.example_method()

Myclass.example_method()
copy
Output:
Hello, World! Traceback (most recent call last):   File "<string>", line 11, in <module> TypeError: Myclass.example_method() missing 1 required positional argument: 'self' [Finished in 0.010297399945557117s]

As shown above, calling the method with the class itself raises an error. By decorating the method with the @classmethod decorator, it effectively becomes accessible from both the class and its objects/instances, as shown below.

ExampleEdit & Run
class Myclass:
    def __init__(self):
        self.name = 'class instance'
    @classmethod
    def example_method(cls):
         print('Hello, World!')

Myclass.example_method()

print('----------------------')

myInstance = Myclass()

myInstance.example_method()
copy
Output:
Hello, World! ---------------------- Hello, World! [Finished in 0.009440698195248842s]

more examples are shown below

class School: 
    instances = 0 #keep count of how many instances are initialised
    def __init__(self): 
         self.name = 'an instance'
         School.instances += 1

def countInstances(cls):
     return cls.instances

School.count_instances = classmethod(countInstances)

S1 = School()
S2 = School()
S3 = School()
S4 = School()

print(School.count_instances())
copy
Output:
4
ExampleEdit & Run
class Library:
    books = []
    authors = []

    def __init__(self,name = None): 
       self.name  = name

    def add_book(self, title, author):
       self.books.append(title)
       self.authors.append(author)
    @classmethod
    def get_authors(cls):
        return cls.authors

    @classmethod
    def get_books(cls):
        return cls.books

    @classmethod
    def get_all(cls):
        return list(zip(cls.books, cls.authors))

myLibrary = Library("John's Library")

b1 = myLibrary.add_book('Book Thief', 'Markus Zusak')
b2 = myLibrary.add_book('Tell me your dreams', 'Sydney Sheldon')
b3 = myLibrary.add_book('Maybe in another life.', 'Taylor Jenkins')

print(Library.get_authors())
print(Library.get_books())
print(Library.get_all())
copy
Output:
['Markus Zusak', 'Sydney Sheldon', 'Taylor Jenkins'] ['Book Thief', 'Tell me your dreams', 'Maybe in another life.'] [('Book Thief', 'Markus Zusak'), ('Tell me your dreams', 'Sydney Sheldon'), ('Maybe in another life.', 'Taylor Jenkins')] [Finished in 0.009476428851485252s]

We also have static methods ,which unlike class methods, have no access to the class state and cannot modify it. Static methods are defined using the builtin @staticmethod decorator/function.