Auto-Vivification in Python

We saw in the earlier post what is auto-vivification and how we can implement it in JavaScript.
Can we do it in Python as well? Yes, Sure.

Python does not have built in auto-vivification

Let's see if it supports it
univ = {}
univ.college.stream.year = 1
''' Output
univ.college.stream.year = 1
AttributeError: 'dict' object has no attribute 'college'
'''
view raw NoAutoViv.py hosted with ❤ by GitHub
No AutoViv in Python

Nope!
So what can we do?
Well, Python is a dynamic language, which allows us not only to add properties (attributes) at runtime but we can also ‘intercept’ calls to attributes which do not exist.

class Univ:
def __init__(self):
# define an attribute
self.name = "ABC"
univ = Univ()
print(univ.name) # This works
print(univ.college) # This gives error
view raw NoAttrib.py hosted with ❤ by GitHub
No Attribute Error

So, can we intercept univ.college access and do something different? Sure

class Univ:
def __init__(self):
self.name = "ABC"
# This gets called when attribute is missing
def __getattr__(self, attribute):
try:
return self[attribute]
except:
return "We are very sorry, we cannot server you that yet"
univ = Univ()
print(univ.name) # Actual attribute
print(univ.college) # Custom response
''' Output
ABC
We are very sorry, we cannot server you that yet
'''
Intercept Attribute

Great, we can intercept calls for missing attributes, but can we create the attribute on the fly? Sure

Magic of dunders ( double underscores)
Here we override __getattr__/__setattr__ for univ.college.stream.year = “A+”
and we override __getitem__ for univ[‘college’][‘stream’][‘year’] = “A+”

auto inherits a dictionary

This way we can store the attributes in “dict” we are inheriting which simplifies our code to bare minimum. We can also show “bravado” and build this WITHOUT inheriting from dict and manage everything ourselves. Perhaps, another blog post?

Over to final code
# auto inherits a dictionary
class auto(dict):
# if caller did univ.college
def __getattr__(self, name):
try:
# check if its there
return dict.__setitem__(self, name)
except:
# if not, create it on the fly
dict.__setitem__(self, name, auto())
return dict.__getitem__(self, name)
# if caller did univ.college = value
def __setattr__(self, name, value):
# set it in internal dict
dict.__setitem__(self, name, value)
# if caller did univ['college]
def __getitem__(self, value):
try:
# if found return it
return dict.__getitem__(self, value)
except:
# if not, create it on the fly
dict.__setitem__(self, value, auto())
return dict.__getitem__(self, value)
univ = auto()
univ.college.stream.year = "A+"
print(univ)
univ2 = auto()
univ2['college']['stream']['year'] = "A+"
print(univ2)
view raw AutoViv.py hosted with ❤ by GitHub
Auto Vivification in Python
And here is the output
univ1 {'college': {'stream': {'year': 'A+'}}}
univ2 {'college': {'stream': {'year': 'A+'}}}

Auto Vivification Series

  1. Auto vivification in JavaScript
  2. Auto vivification in Python
  3. Auto vivification in JavaScript (Upgraded)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s