Python decorator (use it as feature flag)
By: Joe Tang
Tags: Software Testing, Python Programming, Python, Software Engineering

Since I have moved to a new job, Python seems very far away because my company is a Java shop. Until this morning, my old teammate called me and asking some python questions about the python decorator.

After talking to my old teammate, I decided to write a blog to share what I know.

I came up with a python decorator, use it as a feature flag to decide to execute the method. All right, let’s jump to the python code.

Here is my decorator.

def feature_flag(flag):

def decorator_feature_flag(func):

@functools.wraps(func)

def wrapper_decorator_feature_flag(*args, **kwargs):

if flag is "OFF":

func(*args, **kwargs)



return wrapper_decorator_feature_flag



return decorator_feature_flag

Let say my python script has the following methods

def fun_print_profile(profile: dict):

print(profile)



def fun_print_name(profile: dict):

print(profile['name'])



def fun_print_location(profile: dict):

print(profile['location'])



def fun_update_location(profile: dict):

profile["location"] = "San Francisco"

fun_print_profile(profile)

fun_print_location(profile)



def main(my_profile: dict):

fun_print_profile(my_profile)

fun_print_name(my_profile)

fun_print_location(my_profile)

fun_update_location(my_profile)

If we run it (call the main method)

main({"name": "joe", "location": "Bay Area"})

The result will be:

{'name': 'joe', 'location': 'Bay Area'}

joe

Bay Area

{'name': 'joe', 'location': 'San Francisco'}

San Francisco

Well, as of now, nothing is fancy, but if we add the decorator to the method, the entire game change.

@feature_flag('OFF')

def fun_print_profile(profile: dict):

print(profile)



@feature_flag('OFF')

def fun_print_name(profile: dict):

print(profile['name'])



@feature_flag('ON')

def fun_print_location(profile: dict):

print(profile['location'])



@feature_flag('OFF')

def fun_update_location(profile: dict):

profile["location"] = "San Francisco"

fun_print_profile(profile)

fun_print_location(profile)



def main(my_profile: dict):

fun_print_profile(my_profile)

fun_print_name(my_profile)

fun_print_location(my_profile)

fun_update_location(my_profile)

All right, in here, we turn the feature flag ‘ON’ for the fun_print_location method. The goal is not to execute the code inside the method.

Let's run the same command again.

main({"name": "joe", "location": "Bay Area"})

This time the result will be

{'name': 'joe', 'location': 'Bay Area'}

joe

{'name': 'joe', 'location': 'San Francisco'}

If you compare both results (before and after adding the decorator), you will find that the fun_print_location does not get executed even we call it from the main. The reason is we turn the @feature_flag(‘ON’).

If you ask me why do we need a feature flag like that, it will take me another blog to describe. Just keep in mind that I happen to use the feature flag as an example. You can write a decorator for other purposes, like printing a message, etc.

All right now is your time to play around with the script. Try to turn the @feature_flag(‘ON’) or @feature_flag(‘OFF’) to see what happens.

Final code: feature_flag.py

import functools





def feature_flag(flag):

def decorator_feature_flag(func):

@functools.wraps(func)

def wrapper_decorator_feature_flag(*args, **kwargs):

if flag is "OFF":

func(*args, **kwargs)



return wrapper_decorator_feature_flag



return decorator_feature_flag



@feature_flag('OFF')

def fun_print_profile(profile: dict):

print(profile)



@feature_flag('OFF')

def fun_print_name(profile: dict):

print(profile['name'])



@feature_flag('ON')

def fun_print_location(profile: dict):

print(profile['location'])



@feature_flag('OFF')

def fun_update_location(profile: dict):

profile["location"] = "San Francisco"

fun_print_profile(profile)

fun_print_location(profile)



def main(my_profile: dict):

fun_print_profile(my_profile)

fun_print_name(my_profile)

fun_print_location(my_profile)

fun_update_location(my_profile)



main({"name": "joe", "location": "Bay Area"})

I hope you like this blog, and I am welcome all feedback.