Python for the first time

I mentioned in the previous post that I was reading Kent Beck's Test Driven Development by Example, and so far I am learning some unexpected things on top of the TDD techniques.

I learnt an interesting thing about Python among those. Apparently, one of the coolest features of Python is that you can treat the names of classes and methods like functions. So let's see what does it actually gives us.

Say if we had a class Person:

class Person:
  __init__(self, talent)
    self.talent= talent

To create an instance of a class we would do the following:

artist = Person("drawing")

For example, in Ruby, the equivalent would be:

Person.new("drawing")

In many other languages you would use a keyword new, but in Python you treat a class name as a function. So, this is not such a big deal, I hear you say. The real cool thing comes from ability to use attribute values as functions as well, if the attribute value corresponds to the method name:

def drawing(self):
  print("I must have been a Picasso in my previous life!")

So we could do something like:

def show_talent(self):
  method= getattr(self, self.talent)
  method()

So the magic is in these lines:

...
  method= getattr(self, self.talent)
  method()
...

getattr(self, self.talent) returns us the value of the talent attribute for our instance, i.e. "drawing". This value is assigned to a variable method, and then we just invoke the variable as if it was a funciton, because we actually have a method within a class with a name that corresponds to the string "drawing".

And this is pretty awesome, we can dynamically invoke methods specific to the given instance of a class. So we could have persons with different talents, and all we need to do to demonstrate their talent is to call .show_talent().

Let's define another method:

def baking(self):
  print("my cakes are to die for!")

And let's try another instance of Person class:

baker = Person("baking")

So I can just call:

baker.show_talent()
artist.show_talent()

Evenethough, they are both instances of the Person class the method that will be called for as a result is specific to that instance.

Here's the whole class, as it may be easier to see all of it at once, especially, if it is the first time you are looking at Python:

class Person:
  def __init__(self, talent):
    self.talent= talent

  def drawing(self):
    print("I must have been a Picasso in my previous life!")

  def baking(self):
    print("my cakes are to die for!")

  def show_talent(self):
    method= getattr(self, self.talent)
    method()

And this is how we instanciated the class and asked the instance to perform their individual talent for us:

artist = Person("drawing")
artist.show_talent()

baker = Person("baking")
baker.show_talent()

This is my first acquaintance with Python and I am already liking it!

Couple of other things I noticed:

  • All that indentation is not just for readability, it matters, and I like that I can nest code instead of having to write "end" keywords. (I wish Ruby did that!)
  • Kent Beck is using camelCase!! I got excited as I am not a big fan of snake case personally, I find camel case much more elegant. But unfortunately that excitement didn’t get to live long, because apparently general convention for Python is snake case these days, camel case is only acceptable if you are maintaining legacy codebase. Oh well, at least Python had its wild days.
  • I also really enjoyed using parenthesis for method invocation in Python, even if you don’t have arguments. There’s certain satisfaction that comes from such explicitness, there’s no ambiguity whether its a variable or a method name. Of course I could just use them in Ruby, however, rubyists are very opinionated on this matter, we don’t want to be upsetting them.

So far it appears that the language is much more explicit than what I am used to (I obviously have not got to Java yet), and this is a definite win for me!