python staticmethod and classmethod

Though classmethod and staticmethod are quite similar, there’s a slight difference in usage for both entities: classmethod must have a reference to a class object as the first parameter, whereas staticmethod can have no parameters at all.

Let’s look at all that was said in real examples.

Although classMethod and StaticMethod are very similar, there are some obvious differences in usage. Classmethod must have a reference to the class object as its first argument, whereas staticMethod can have no arguments at all.

Let’s look at some examples.

Example – Boilerplate

Let’s assume an example of a class, dealing with date information (this is what will be our boilerplate to cook on):

class Date(object):
 
    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = yearCopy the code

This class obviously could be used to store information about certain dates (without timezone information; let’s assume all dates are presented in UTC).

Obviously, objects of this class can store date information (not including time zones, assuming they are all stored in UTC).

Here we have __init__, a typical initializer of Python class instances, which receives arguments as a typical instancemethod, having the first non-optional argument (self) that holds reference to a newly created instance.

The init method here initializes the property of the object, and its first argument must be self, which points to the already created object.

Class Method

We have some tasks that can be nicely done using classmethods.

Let’s assume that we want to create a lot of Date class instances having Date information coming from outer source Encoded as a string of next format (‘ DD-MM-YYYY ‘). We have to do that in different places of our source code in project.

You can do some really cool stuff with ClassMethod.

For example, we can support creating objects from date strings in a specific format (‘ DD-MM-YYYY ‘). Obviously, we have to implement this in other places than the init method.

So what we must do here is:

Parse a string to receive day, month and year as three integer variables or a 3-item tuple consisting of that variable.

Instantiate Date by passing those values to initialization call.

This will look like:

General steps:

  • Parse the string to get the integers day, month, and year.
  • Use the resulting information to initialize the object

The following code

day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)Copy the code

Ideally, the Date class itself would have the ability to handle string times, eliminating reusability issues such as adding an extra method.

For this purpose, C++ has such feature as overloading, But Python lacks that feature-so here’s when classmethod applies. Lets create another “constructor”.

C++ can easily use overloading to solve this problem, but python does not have a similar feature. So we’re going to use classMethod to do that for us.

@classmethod
  def from_string(cls, date_as_string):
  day, month, year = map(int, date_as_string.split('-'))
  date1 = cls(day, month, year)
  return date1
 
 
date2 = Date.from_string('11-09-2012')Copy the code

Let’s look more carefully at the above implementation, and review what advantages we have here:

We’ve implemented date string parsing in one place and it’s Free now. Encapsulation works fine here (if you think that you could implement string parsing as a single function elsewhere, this solution fits OOP paradigm far better). cls is an object that holds class itself, Not an instance of the class. It’s pretty cool because if we inherit our Date class, all children will have from_string defined also.

Let’s take a closer look at the above implementation to see its benefits.

We implemented the functionality in a method, so it is reusable. Encapsulation works fine here (if you find that you can add a function anywhere in your code that doesn’t belong to Date to do something similar, then this is clearly more OOP compliant). CLS is an object that holds a class (everything is an object). Even better, any derived class of the Date class will have a useful method called from_string.

Static method

What about staticmethod? It’s pretty similar to classmethod but doesn’t take any obligatory parameters (like a class method or instance method does).

Let’s look at the next use case.

We have a date string that We want to validate somehow. This task is also caribbeanbound to date class We’ve used so Far, but still doesn’t require instantiation of it.

Here is where staticmethod can be useful. Let’s look at the next piece of code:

Staticmethod takes no mandatory parameters, whereas classmethod always takes CLS and instancemethod always takes self.

@staticmethod
def is_date_valid(date_as_string):
  day, month, year = map(int, date_as_string.split('-'))
  return day <= 31 and month <= 12 and year <= 3999
 
# usage:
is_date = Date.is_date_valid('11-09-2012')Copy the code

So, as we can see from usage of staticmethod, we don’t have any access to what the class is- it’s basically just a function, called syntactically like a method, but without access to the object and it’s internals (fields and another methods), while classmethod does.

So, as you can see from our use of static methods, we don’t access the class itself — it’s basically just a function, syntactically like a method, but instead of accessing the object and its internals (fields and other methods), classMethod accesses CLS, Instancemethod accesses self.

reference

  • Meaning of @classmethod and @staticmethod for beginner?



1 comment