What is the purpose of class methods?

Viewed 150493

I'm teaching myself Python and my most recent lesson was that Python is not Java, and so I've just spent a while turning all my Class methods into functions.

I now realise that I don't need to use Class methods for what I would done with static methods in Java, but now I'm not sure when I would use them. All the advice I can find about Python Class methods is along the lines of newbies like me should steer clear of them, and the standard documentation is at its most opaque when discussing them.

Does anyone have a good example of using a Class method in Python or at least can someone tell me when Class methods can be sensibly used?

18 Answers

Class methods are for when you need to have methods that aren't specific to any particular instance, but still involve the class in some way. The most interesting thing about them is that they can be overridden by subclasses, something that's simply not possible in Java's static methods or Python's module-level functions.

If you have a class MyClass, and a module-level function that operates on MyClass (factory, dependency injection stub, etc), make it a classmethod. Then it'll be available to subclasses.

Factory methods (alternative constructors) are indeed a classic example of class methods.

Basically, class methods are suitable anytime you would like to have a method which naturally fits into the namespace of the class, but is not associated with a particular instance of the class.

As an example, in the excellent unipath module:

Current directory

  • Path.cwd()
    • Return the actual current directory; e.g., Path("/tmp/my_temp_dir"). This is a class method.
  • .chdir()
    • Make self the current directory.

As the current directory is process wide, the cwd method has no particular instance with which it should be associated. However, changing the cwd to the directory of a given Path instance should indeed be an instance method.

Hmmm... as Path.cwd() does indeed return a Path instance, I guess it could be considered to be a factory method...

Alternative constructors are the classic example.

When a user logs in on my website, a User() object is instantiated from the username and password.

If I need a user object without the user being there to log in (e.g. an admin user might want to delete another users account, so i need to instantiate that user and call its delete method):

I have class methods to grab the user object.

class User():
    #lots of code
    #...
    # more code

    @classmethod
    def get_by_username(cls, username):
        return cls.query(cls.username == username).get()

    @classmethod
    def get_by_auth_id(cls, auth_id):
        return cls.query(cls.auth_id == auth_id).get()

Honestly? I've never found a use for staticmethod or classmethod. I've yet to see an operation that can't be done using a global function or an instance method.

It would be different if python used private and protected members more like Java does. In Java, I need a static method to be able to access an instance's private members to do stuff. In Python, that's rarely necessary.

Usually, I see people using staticmethods and classmethods when all they really need to do is use python's module-level namespaces better.

I used to work with PHP and recently I was asking myself, whats going on with this classmethod? Python manual is very technical and very short in words so it wont help with understanding that feature. I was googling and googling and I found answer -> http://code.anjanesh.net/2007/12/python-classmethods.html.

If you are lazy to click it. My explanation is shorter and below. :)

in PHP (maybe not all of you know PHP, but this language is so straight forward that everybody should understand what I'm talking about) we have static variables like this:


class A
{

    static protected $inner_var = null;

    static public function echoInnerVar()
    {
        echo self::$inner_var."\n";
    }

    static public function setInnerVar($v)
    {
        self::$inner_var = $v;
    }

}

class B extends A
{
}

A::setInnerVar(10);
B::setInnerVar(20);

A::echoInnerVar();
B::echoInnerVar();

The output will be in both cases 20.

However in python we can add @classmethod decorator and thus it is possible to have output 10 and 20 respectively. Example:


class A(object):
    inner_var = 0

    @classmethod
    def setInnerVar(cls, value):
        cls.inner_var = value

    @classmethod
    def echoInnerVar(cls):
        print cls.inner_var


class B(A):
    pass


A.setInnerVar(10)
B.setInnerVar(20)

A.echoInnerVar()
B.echoInnerVar()

Smart, ain't?

if you are not a "programmer by training", this should help:

I think I have understood the technical explanations above and elsewhere on the net, but I was always left with a question "Nice, but why do I need it? What is a practical, use case?". and now life gave me a good example that clarified all:

I am using it to control the global-shared variable that is shared among instances of a class instantiated by multi-threading module. in humane language, I am running multiple agents that create examples for deep learning IN PARALLEL. (imagine multiple players playing ATARI game at the same time and each saving the results of their game to one common repository (the SHARED VARIABLE))

I instantiate the players/agents with the following code (in Main/Execution Code):

a3c_workers = [A3C_Worker(self.master_model, self.optimizer, i, self.env_name, self.model_dir) for i in range(multiprocessing.cpu_count())]
  • it creates as many players as there are processor cores on my comp A3C_Worker - is a class that defines the agent a3c_workers - is a list of the instances of that class (i.e. each instance is one player/agent)

now i want to know how many games have been played across all players/agents thus within the A3C_Worker definition I define the variable to be shared across all instances:

class A3C_Worker(threading.Thread):
   global_shared_total_episodes_across_all_workers = 0

now as the workers finish their games they increase that count by 1 each for each game finished

at the end of my example generation i was closing the instances but the shared variable had assigned the total number of games played. so when I was re-running it again my initial total number of episodes was that of the previous total. but i needed that count to represent that value for each run individually

to fix that i specified :

class A3C_Worker(threading.Thread):
    @classmethod
    def reset(cls):
        A3C_Worker.global_shared_total_episodes_across_all_workers = 0

than in the execution code i just call:

A3C_Worker.reset()

note that it is a call to the CLASS overall not any INSTANCE of it individually. thus it will set my counter to 0 for every new agent I initiate from now on.

using the usual method definition def play(self):, would require us to reset that counter for each instance individually, which would be more computationally demanding and difficult to track.

@classmethod can be useful for easily instantiating objects of that class from outside resources. Consider the following:

import settings

class SomeClass:
    @classmethod
    def from_settings(cls):
        return cls(settings=settings)

    def __init__(self, settings=None):
        if settings is not None:
            self.x = settings['x']
            self.y = settings['y']

Then in another file:

from some_package import SomeClass

inst = SomeClass.from_settings()

Accessing inst.x will give the same value as settings['x'].

Classes and Objects concepts are very useful in organizing things. It's true that all the operations that can be done by a method can also be done using a static function.

Just think of a scenario, to build a Students Databases System to maintain student details. You need to have details about students, teachers and staff. You need to build functions to calculate fees, salary, marks, etc. Fees and marks are only applicable for students, salary is only applicable for staff and teachers. So if you create separate classes for every type of people, the code will be organized.

Related