What is the purpose of class methods?
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?
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:
- Return the actual current directory; e.g.,
Path("/tmp/my_temp_dir"). This is a class method.
- Return the actual current directory; e.g.,
- 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.
Path.cwd() does indeed return a
Path instance, I guess it could be considered to be a factory method…
Think about it this way: normal methods are useful to hide the details of dispatch: you can type
myobj.foo() without worrying about whether the
foo() method is implemented by the
myobj object’s class or one of its parent classes. Class methods are exactly analogous to this, but with the class object instead: they let you call
MyClass.foo() without having to worry about whether
foo() is implemented specially by
MyClass because it needed its own specialized version, or whether it is letting its parent class handle the call.
Class methods are essential when you are doing set-up or computation that precedes the creation of an actual instance, because until the instance exists you obviously cannot use the instance as the dispatch point for your method calls. A good example can be viewed in the SQLAlchemy source code; take a look at the
dbapi() class method at the following link:
You can see that the
dbapi() method, which a database backend uses to import the vendor-specific database library it needs on-demand, is a class method because it needs to run before instances of a particular database connection start getting created — but that it cannot be a simple function or static function, because they want it to be able to call other, supporting methods that might similarly need to be written more specifically in subclasses than in their parent class. And if you dispatch to a function or static class, then you “forget” and lose the knowledge about which class is doing the initializing.
I recently wanted a very light-weight logging class that would output varying amounts of output depending on the logging level that could be programmatically set. But I didn’t want to instantiate the class every time I wanted to output a debugging message or error or warning. But I also wanted to encapsulate the functioning of this logging facility and make it reusable without the declaration of any globals.
So I used class variables and the
@classmethod decorator to achieve this.
With my simple Logging class, I could do the following:
Logger._level = Logger.DEBUG
Then, in my code, if I wanted to spit out a bunch of debugging information, I simply had to code
Logger.debug( "this is some annoying message I only want to see while debugging" )
Errors could be out put with
Logger.error( "Wow, something really awful happened." )
In the “production” environment, I can specify
Logger._level = Logger.ERROR
and now, only the error message will be output. The debug message will not be printed.
Here’s my class:
class Logger : ''' Handles logging of debugging and error messages. ''' DEBUG = 5 INFO = 4 WARN = 3 ERROR = 2 FATAL = 1 _level = DEBUG def __init__( self ) : Logger._level = Logger.DEBUG @classmethod def isLevel( cls, level ) : return cls._level >= level @classmethod def debug( cls, message ) : if cls.isLevel( Logger.DEBUG ) : print "DEBUG: " + message @classmethod def info( cls, message ) : if cls.isLevel( Logger.INFO ) : print "INFO : " + message @classmethod def warn( cls, message ) : if cls.isLevel( Logger.WARN ) : print "WARN : " + message @classmethod def error( cls, message ) : if cls.isLevel( Logger.ERROR ) : print "ERROR: " + message @classmethod def fatal( cls, message ) : if cls.isLevel( Logger.FATAL ) : print "FATAL: " + message
And some code that tests it just a bit:
def logAll() : Logger.debug( "This is a Debug message." ) Logger.info ( "This is a Info message." ) Logger.warn ( "This is a Warn message." ) Logger.error( "This is a Error message." ) Logger.fatal( "This is a Fatal message." ) if __name__ == '__main__' : print "Should see all DEBUG and higher" Logger._level = Logger.DEBUG logAll() print "Should see all ERROR and higher" Logger._level = Logger.ERROR logAll()
Alternative constructors are the classic example.
I think the most clear answer is AmanKow’s one. It boils down to how u want to organize your code. You can write everything as module level functions which are wrapped in the namespace of the module i.e
module.py (file 1) --------- def f1() : pass def f2() : pass def f3() : pass usage.py (file 2) -------- from module import * f1() f2() f3() def f4():pass def f5():pass usage1.py (file 3) ------------------- from usage import f4,f5 f4() f5()
The above procedural code is not well organized, as you can see after only 3 modules it gets confusing, what is each method do ? You can use long descriptive names for functions(like in java) but still your code gets unmanageable very quick.
The object oriented way is to break down your code into manageable blocks i.e Classes & objects and functions can be associated with objects instances or with classes.
With class functions you gain another level of division in your code compared with module level functions.
So you can group related functions within a class to make them more specific to a task that you assigned to that class. For example you can create a file utility class :
class FileUtil (): def copy(source,dest):pass def move(source,dest):pass def copyDir(source,dest):pass def moveDir(source,dest):pass //usage FileUtil.copy("1.txt","2.txt") FileUtil.moveDir("dir1","dir2")
This way is more flexible and more maintainable, you group functions together and its more obvious to what each function do. Also you prevent name conflicts, for example the function copy may exist in another imported module(for example network copy) that you use in your code, so when you use the full name FileUtil.copy() you remove the problem and both copy functions can be used side by side.