Automatic Type Conversion in Runtime | Python

Automatic Type Conversion in Runtime | Python

Hi. I am back with an exciting topic in python.

How many times you have come across functions which automatically convert your values to required types in runtime?

For e.g. In Django whenever you define your types like this in route definitions the URL parameters are automatically parsed inside of your function.

urlpatterns = [

path("/<str:slug>", someRandomView, name="home"),
path("/<int:pk>", someRandomProfile, name="home_profile")

]

So whenever you define your views, your data types are automatically converted to the required data type.

def someRandomView(slug):
  ...

def someRandomProfile(pk):
  ...

This offers a huge convenience in your application by automatically converting your type as per your function or something hints the function wants to achieve.

Similar behavior is achieved in fast API.

Let’s define a simple function.

def getAge(age, name):
    print( f" {age} : {type(age)} , {name} : {type(name)} " )

You can see our types are nowhere defined in this piece of code. But, we can guess the user wants to age as an int variable and name as an str variable ( most probably). But python doesn’t work that way. You can call that function with any variable you want.

It would be a lot better if your code automatically gave the developer some idea about data types.

Let’s refactor that piece of code a little bit.

def getAge(age: int, name: str):
    print( f" {age} : {type(age)} , {name} : {type(name)} " )

Now, this code is a lot cleaner than your previous code. But, we still have the same problem but it aids a little bit. Your text editor may flag out wrong parameter types if you’re using some linters or running on mypy.

But, what we wanted to achieve is to make automatic type conversions in runtime. So, whenever you call the function, your arguments are automatically parsed to be converted into required data types.

Let’s try writing a decorator to print what exactly we can extract out of the function definition.

from typing import Callable

def decorator(func: Callable):

    def inner_func(*args, **kwargs):
        print(kwargs, func.__annotations__)
        func(*args, **kwargs)

    return inner_func


@decorator
def getAge(age: int, name: str):
    print( f" {age} : {type(age)} , {name} : {type(name)} " )

When we call the function using getAge(age=12,name=”Mahesh”), this is the output we get.

kwargs: {'age': 12, 'name': 'mahesh'}
__annotations__ : {'age': <class 'int'>, 'name': <class 'str'>}

Now, this makes sense. Your annotations are extracted from your function in the compile time of the function and not changed by your arguments.

So, to achieve automatic type conversion on the function, we can write all the code to convert types as mentioned in the function annotations.

#/bin/env python
from typing import Callable
def decorator(function: Callable):

    def inner_function(*args, **kwargs):

        newKwargs = {}

        for argName, typeName in function.__annotations__.items():
            if typeName is int:
                intVar = int(kwargs[argName])
                newKwargs[argName] = intVar
            elif typeName is str:
                strVar = str(kwargs[argName])
                newKwargs[argName] = strVar
        function(*args, **newKwargs)

    return inner_function


@decorator
def getAge(age: int, name: str):
    print( f" {age} : {type(age)} , {name} : {type(name)} " )

And boom, this works!

Whenever you call the function, it gets automatically converted to the required type and if it fails, it will throw the value error.