In the previous three posts of this series I evaluated three core tenets of object oriented programming and how well (or not well) Python implements them. Those tenets were polymorphism, inheritance, and encapsulation.
Before I state my conclusion, I want to point out one more aspect of object oriented programming in Python which I find awkward. In object oriented languages, it is typically understood from the context what are object methods and which are class functions. In Java for example, the ‘static’ keyword creates a static function. Non-static methods are associated with instances of the object.
public class Person { private name; public Person() { this.name = name; } public void sayHello() { System.out.println("Hello, my name is " + this.name); } public static void sayHello(Person person) { System.out.println("Hi there " + person.name); } }
Even if you don’t know Java, it’s easy to tell which method is associated with the object and which one is static. Notice that the default here is that the definition is an object method. To me, that makes sense and should be the default in an object oriented language.
Python though, awkwardly enough, has no default. It makes absolutely, positively, no sense. Python syntax requires that object methods pass a reference to ‘self’ as the first argument to an object method. That is, an object method say hello looks like this:
def say_hello(self): print("Hello, my name is " + self.name)
It just seems out of place and adds useless parameters to a function. Self should be (and could be) implied by the context.
So then, one might think that if we omit the ‘self’ argument, that it would make this a static method, right? WRONG! To create a Person.say_hello static method you instead have to add a ‘@staticmethod’ decorator like so:
@staticmethod def say_hello(person): print("Hello there " + person.name)
So, in order to create object methods we need to add a ‘self’ reference and to create static methods we need to add the @staticmethod decorator. This is why I say that Python has no default. Sure, your IDE helps you by automatically adding the self reference when you define your methods, but why can’t the interpreter figure this out? Other languages don’t make you pass around useless function arguments like this.
In conclusion, Python seems to be hacked together with little band-aid fixes here and there to make it more object oriented. It’s like that old legacy codebase that has methods with 22 boolean flags in a method signature to get around bugs because nobody could detangle the web of code to actually implement a good fix. As an object oriented language, Python received a failing grade.
There are some cool things you can do with Python and it definitely has its uses. Python is popular because of these capabilities and not on its merits as a clean, well-implemented language. I recommend checking out the Python Tricks post on Pluralsight for some nice Python-isms.
Python can be a lot of fun to code with. It doesn’t get in your way, it has some nice features for working with arrays — I mean lists — and some cool little syntax tricks not found in many other languages. But, it can also be really confusing. As a Python n00b, I have found myself looking at some lines of code written by more experienced Pythoners with a blank stare. Like, why the hell does this ‘for’ statement have an ‘else’ block?! What is that?! Anyway, enough griping 🙂
My Python adventure will continue as I start to use some of its more popular libraries for AI and ML and I am sure it will grow on me over time just as Javascript has. At least, I hope it will.