[python] Meaning of @classmethod and @staticmethod for beginner?

Meaning of @classmethod and @staticmethod?

  • A method is a function in an object's namespace, accessible as an attribute.
  • A regular (i.e. instance) method gets the instance (we usually call it self) as the implicit first argument.
  • A class method gets the class (we usually call it cls) as the implicit first argument.
  • A static method gets no implicit first argument (like a regular function).

when should I use them, why should I use them, and how should I use them?

You don't need either decorator. But on the principle that you should minimize the number of arguments to functions (see Clean Coder), they are useful for doing just that.

class Example(object):

    def regular_instance_method(self):
        """A function of an instance has access to every attribute of that 
        instance, including its class (and its attributes.)
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_f(self)

    @classmethod
    def a_class_method(cls):
        """A function of a class has access to every attribute of the class.
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_g(cls)

    @staticmethod
    def a_static_method():
        """A static method has no information about instances or classes
        unless explicitly given. It just lives in the class (and thus its 
        instances') namespace.
        """
        return some_function_h()

For both instance methods and class methods, not accepting at least one argument is a TypeError, but not understanding the semantics of that argument is a user error.

(Define some_function's, e.g.:

some_function_h = some_function_g = some_function_f = lambda x=None: x

and this will work.)

dotted lookups on instances and classes:

A dotted lookup on an instance is performed in this order - we look for:

  1. a data descriptor in the class namespace (like a property)
  2. data in the instance __dict__
  3. a non-data descriptor in the class namespace (methods).

Note, a dotted lookup on an instance is invoked like this:

instance = Example()
instance.regular_instance_method 

and methods are callable attributes:

instance.regular_instance_method()

instance methods

The argument, self, is implicitly given via the dotted lookup.

You must access instance methods from instances of the class.

>>> instance = Example()
>>> instance.regular_instance_method()
<__main__.Example object at 0x00000000399524E0>

class methods

The argument, cls, is implicitly given via dotted lookup.

You can access this method via an instance or the class (or subclasses).

>>> instance.a_class_method()
<class '__main__.Example'>
>>> Example.a_class_method()
<class '__main__.Example'>

static methods

No arguments are implicitly given. This method works like any function defined (for example) on a modules' namespace, except it can be looked up

>>> print(instance.a_static_method())
None

Again, when should I use them, why should I use them?

Each of these are progressively more restrictive in the information they pass the method versus instance methods.

Use them when you don't need the information.

This makes your functions and methods easier to reason about and to unittest.

Which is easier to reason about?

def function(x, y, z): ...

or

def function(y, z): ...

or

def function(z): ...

The functions with fewer arguments are easier to reason about. They are also easier to unittest.

These are akin to instance, class, and static methods. Keeping in mind that when we have an instance, we also have its class, again, ask yourself, which is easier to reason about?:

def an_instance_method(self, arg, kwarg=None):
    cls = type(self)             # Also has the class of instance!
    ...

@classmethod
def a_class_method(cls, arg, kwarg=None):
    ...

@staticmethod
def a_static_method(arg, kwarg=None):
    ...

Builtin examples

Here are a couple of my favorite builtin examples:

The str.maketrans static method was a function in the string module, but it is much more convenient for it to be accessible from the str namespace.

>>> 'abc'.translate(str.maketrans({'a': 'b'}))
'bbc'

The dict.fromkeys class method returns a new dictionary instantiated from an iterable of keys:

>>> dict.fromkeys('abc')
{'a': None, 'c': None, 'b': None}

When subclassed, we see that it gets the class information as a class method, which is very useful:

>>> class MyDict(dict): pass
>>> type(MyDict.fromkeys('abc'))
<class '__main__.MyDict'> 

My advice - Conclusion

Use static methods when you don't need the class or instance arguments, but the function is related to the use of the object, and it is convenient for the function to be in the object's namespace.

Use class methods when you don't need instance information, but need the class information perhaps for its other class or static methods, or perhaps itself as a constructor. (You wouldn't hardcode the class so that subclasses could be used here.)

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to oop

How to implement a simple scenario the OO way When to use 'raise NotImplementedError'? PHP: cannot declare class because the name is already in use Python class input argument Call an overridden method from super class in typescript Typescript: How to extend two classes? What's the difference between abstraction and encapsulation? An object reference is required to access a non-static member Java Multiple Inheritance Why not inherit from List<T>?

Examples related to static-methods

How to verify static void method has been called with power mockito Calling class staticmethod within the class body? Meaning of @classmethod and @staticmethod for beginner? Difference between Static methods and Instance methods How can I solve "Non-static method xxx:xxx() should not be called statically in PHP 5.4? How to call getClass() from a static method in Java? Cannot make a static reference to the non-static method calling another method from the main method in java When to use static methods Why doesn't Java allow overriding of static methods?

Examples related to class-method

Meaning of @classmethod and @staticmethod for beginner? How to make a class property? Ruby: Calling class method from instance Calling C++ class methods via a function pointer What is the difference between class and instance methods? What is the purpose of class methods?