Tuesday, November 20, 2018

Python's classmethod and staticmethod

The class method and @classmethod Decorator

A class method is a method that is bound to a class rather than its object. It doesn't require creation of a class instance.The @classmethod decorator exists so you can create class methods that are passed the actual class object within the function call, much like self is passed to any other ordinary instance method in a class.

In those instance methods, the self argument is the class instance object itself, which can then be used to act on instance data. @classmethod methods also have a mandatory first argument, but this argument isn't a class instance, it's actually the uninstantiated class itself.

Let's create @classmethod decorator in our Motorbike class which we have used before. The code is shown below:

class Motorbike():
   
    parking_charges = 100
    def __init__(self,name,color,purpose):
       
        self.name=name
        self.color=color
        self.purpose=purpose
        self.charges=700
       
       
    def bike_description(self):
       
        print("\nYou just got " + self.name + " bike of " + self.color + " color in your garage for " + self.purpose )
       
    def get_amount(self):
       
        print("\nThe minimum servicing charges for the bike is " + str(self.charges))
       
    def billing_amount(self,final_amount):
       
        self.final_amount=final_amount
        print("\nThe final servicing charges for the bike is " + str(self.final_amount))
       
    def new_amount(self,final_amount):
        self.final_amount+=self.parking_charges
       
        print("\nThe net payable charges for the bike is " + str(self.final_amount))
       
    @classmethod
   
    def change_parking_charges(cls,new_parking_charges):
       
        cls.parking_charges = new_parking_charges
       
   
my_bike = Motorbike('Honda','white','servicing')

my_bike.bike_description()
my_bike.get_amount()
my_bike.billing_amount(900)
my_bike.new_amount(900)

Motorbike.change_parking_charges(150)
print("\nNew parking charges changed using @classmethod:\n")
print(my_bike.parking_charges)


In the above shown program the regular method change_parking_charges() has been converted into the class method using the decorator @classmethod at the top.

In the change_parking_charges(cls,amt) method, the first argument cls represents the class. The syntax cls.parking_charges = new_parking_charges sets the parking_charges class variable to the new_parking_charges value, which is passed by the line Motorbike.change_parking_charges(150)

The line Motorbike.change_parking_charges(150) calls the class method change_parking_charges() using the class. We can also use the class instance my_bike to call the class method change_parking_charges() as shown below:

my_bike.change_parking_charges(250)
print("\nNew parking charges changed using instance\n")
print(my_bike.parking_charges)

The output of the program is shown below:




The static method and @staticmethod decorator


The static method doesn't take an instance or class as the first argument. They are just
simple functions. But we include them in class because they have some logical connection
with the class.

Let us consider a situation in our Motorbike class, when any vehicle was parked for more than one day his final bill amount include parking charges else only servicing charges are taken. To turn a regular method into a class method, we will use decorator (@staticmethod) at the top of the method. See the program below:

class Motorbike():
   
    parking_charges = 100
    def __init__(self,name,color,purpose):
       
        self.name=name
        self.color=color
        self.purpose=purpose
        self.min_billing_amount=700
       
       
    @staticmethod
   
    def check_parking_status(parking_amt_payed):
       
        if     parking_amt_payed >0:
           
            return True
           
        else:
           
            return False
   
    def billing_amount(self,new_amount,pc):
       
        self.new_amount = new_amount
        self.pc = pc
       
        if self.check_parking_status(self.pc):
           
            self.new_amount = self.new_amount + self.pc
            return self.new_amount
           
        else:
           
                       
            return self.new_amount
       
       
my_bike = Motorbike('Honda','white','servicing')
my_bike1= Motorbike('Enfield','grey','Repairing')

print(my_bike.billing_amount(1000,0))
print(my_bike.billing_amount(1000,200))

 
In the preceding program, the check_parking_status() method is a static method as specified by the decorator @staticmethod. The check_parking_status() method checks whether amt is greater than 0 or not. The billing_amount() method uses the check_parking_status() static method. The check_parking_status() method does not change the class and instance variable. But it has some logical connection with regular method billing_amount().

The output of the program is shown below:



For Honda bike parking charges are 0 which means vehicle was not parked in the service station hence only servicing charges were taken. For Enfield parking charges are mentioned 200 thus final billing amount is 1200

classmethod VS staticmethod
  • A class method takes cls as first parameter while a static method needs no specific parameters.
  • A class method can access or modify class state while a static method can’t access or modify it.
  • In general, static methods know nothing about class state. They are utility type methods that take some parameters and work upon those parameters. On the other hand class methods must have class as parameter.
  • We use @classmethod decorator in python to create a class method and we use @staticmethod decorator to create a static method in python.
When to use what?

We generally use class method to create factory methods. Factory methods return class object ( similar to a constructor ) for different use cases.

We generally use static methods to create utility functions.

It is advisable to make some of your own class methods and static methods as the concept is not straight forward and requires some practice. In the next post we'll learn about private variable in Python. Till then keep learning Python as Python is easy to learn!
Share:

Monday, November 19, 2018

Decorators in Python

A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. This is also called meta-programming as a part of the program tries to modify another part of the program at compile time. Thus decorators allow you to make simple modifications to callable objects like functions, methods, or classes.

A few facts about functions is worth knowing to have a better understanding about decorator.

1. Different names can be bound to the same function object. For example -

    def display(msg):
          print(msg) 

    display("Decorators")
    new_display = display
    new_display("Decorators")

When we run the code, both functions display and new_display gives same output. Here, the names display and new_display refer to the same function object.

2. Functions can be passed as arguments to another function. In the code shown below this behavior is shown -

def incrementing(x):
return x + 1

def decreasing(x):

return x - 1

def operation(func, x):

result = func(x)
return result

value = operation(incrementing,5)

print(value)

The output of this program is shown below -




  
3. A function can return another function.

def operation ():
   
    def incrementing(x):
       
        x = x+1
        print(x)
    return incrementing   
   
       
val = operation()

val(6)
 

val(8)    

Here, incrementing() is a nested function which is defined and returned, each time we call operation (). See the output below -

 

 So based on the definition that a decorator takes in a function, adds some functionality and returns it, here is an example -


 def operation (func):
  
    def incrementing(x):
      
        x = x+1
        print("incrementing\n")
        print(x)
        func(x)
    return incrementing  
  
      
def reincreasing(x):
  
    x= x + 1
    print("\nreincreasing\n")
    print(x)
  
    return reincreasing


val = operation(reincreasing)

val(20)


The output of the program is shown below -

 


In the example shown above, operation () is a decorator. In the assignment step -

val = operation(reincreasing)

The function reincreasing() got decorated and the returned function was given the name val.

We can see that the decorator function added some new functionality to the original function. This is similar to packing a gift. The decorator acts as a wrapper. The nature of the object that got decorated (actual gift inside) does not alter. But now, it looks pretty (since it got decorated).

Generally, we decorate a function and reassign it as,

reincreasing = operation(reincreasing)

This is a common construct and for this reason, Python has a syntax to simplify this. We can use the @ symbol along with the name of the decorator function and place it above the definition of the function to be decorated. For example,

@operation
def reincreasing():
    x= x + 1
    print("\nreincreasing\n")
    print(x)
    return reincreasing

is equivalent to

def reincreasing():
    x= x + 1
    print("\nreincreasing\n")
    print(x)
    return reincreasing

reincreasing = operation(reincreasing)


In the next post we'll focus on classmethod decorators and static method decorators. Till then keep learning Python as Python is easy to learn!
Share: