A long time ago, circa 1999, when I was working in a certain procedural language I found a library that added objects to the language. It did so by playing interesting tricks with key/value structures, which in Python are called dictionaries. In 2005, as a new Python user, I read something about how objects in Python are essentially dictionaries with syntactical sugar.
Well, today while driving from Los Angeles to San Francisco, I started to try and figure out how to replicate object or class-like behavior using Python dictionaries. In this exercise, I wanted to code out the following:
- methods with ability to write to self/this/whatever
The result isn't something I would use in production code, but it was fun to write. Without further ado...
I present the 'newclass' function!
What newclass does is simple:
- Document implementation of inheritance.
- Include a simple set method for setting attribute values to self/this/whatever.
def newclass(**kwargs): """ Use kwargs.update() method to handle inheritance """ def set(key, value): """ Sets key/value to the kwargs. Replicates self/this clumsily """ kwargs[key] = value kwargs['set'] = set return kwargs
Now that you've seen the code, let's try it out.
Demonstration: Methods with ability to write to self/this/whatever
Instantiating a newclass 'object' is straight-forward. See below:
Setting a value to an attribute can be done via the set method is not pretty, but it works. Yes, you can shortcut set, but I wanted to see if it worked. That it's working is important because since set works, it means we can create much more complicated methods that touch on many parts of the newclass object context.
Just like a normal Python class and method.
Here I show how to use the dict.update() method to display inheritance. I'll demonstrate via the use of the Mammal/Cat/Dog example.
def Mammal(**kwargs): """ The mammal base class """ # dict.update handles the role of inheritance kwargs.update(newclass()) # Mammals have 4 legs kwargs['legs'] = 4 # Using lambda cause I'm lazy. kwargs['say'] = lambda: NotImplemented return kwargs def Cat(**kwargs): # dict.update handles the role of inheritance kwargs.update(Mammal()) # Make a sound kwargs['say'] = lambda: "Meow" return kwargs def Dog(**kwargs): # dict.update handles the role of inheritance kwargs.update(Mammal()) # dict.update handles the role of inheritance # Make a sound kwargs['say'] = lambda: "Bark" return kwargs
Alright, we have our code. What happens when we try it out?
>>> # first we try just the Mammal >>> mammal = Mammal() >>> print(mammal['say']()) NotImplemented >>> print(mammal['legs']) 4 >>> # Now the Cat >>> cat = Cat() >>> print(cat['say']()) Meow >>> print(cat['legs']) 4 >>> # Finally the dog >>> dog = Dog() >>> print(dog['say']()) Bark >>> print(dog['legs']) 4
Compared to normal Python classes the syntax is a little bit on the ugly side. Yet this works and as I said earlier, it was fun to write.
- Should I change the name of the internal context variable from kwargs to self?
- How fast is newclass compared to the standard Python class system?
- What happens if you use newclass in a complex project?
- Shouldn't I implement some way to track inheritance chains? Wouldn't it be nice to know the parent of an object?