Why I Still Choose Python
If you have a look at the projects sections you will find out that most of the projects I'm working on are implemented in the python programming language. Because of that I'm earing lots of criticism on #ruby-lang. But there are in fact reasons for that.
Language Design
A recent discussion with someone (which will go unnamed) again showed up that many people think python has a bad language design. Things that are "wrong" or missing in python are:
- continuation support
- ruby like blocks
- anonymous functions
- weak functional programming support
- statements that aren't expressions (assignments)
- bad object orientation
Interestingly just one of this points is a problem for me. The latter. I would really like to have assignments as expressions but I can also understand Guido who wants to avoid mistakes in the application logic that are caused by an assignment which should be an comparison.
Now to the items on the list. Especially the missing continuation support. Because I never was in a situation where I needed them. By now I could solve all of my problems using generators or context managers.
Because of the fact that python functions are objects I can define them in any namespace. A function in a function doesn't look like an anonymous one but semantically there are few differences. And if you say there is a weak functional programming support I cannot assent. Python has list comprehensions, generator expressions, first class functions and there are libraries that enable currying.
And now to the bad object orientation. Some people think the python object system is bad because it's flange mounted (the explicit self) or because some functions like len() are globals and not instance methods. The excplicit self is something you have to live with. There are some reasons for that implementation detail, one of them is that python doesn't have a ruby like super. Instead of calling a method of the superclass you just call a method of any class in the MRO and provide the self (MyClass.my_method(self, arguments, go='here')). That is much nicer than MyClass.method(:my_method).bind(self).call(arguments, :go => "here") like you do in ruby.
The global functions on the other side are something that is indeed interesting. When I first worked with Python i wondered why some functions are global. Among those are len(), str(), abs() etc. But the idea is in my eyes a very good one. Instead of adding a property called .length to an object you provide a method named __len__() which will be called by the global len() function. The big advantage: You can still use .length for whatever you want, type checks for hasattr(foo, '__len__') won't yield wrong results because __len__ is a special method and doing something else than returning the length of an object is just silly. I know a lot of programming languages (For example C#) where different objects have different size methods/properties (Size, Length, Count) and without and IDE or a good memory you have to have a look at the documentation then.
The str() in the last paragraph is global too. But not a function. It's the class of strings and because of that not an instance method. To control the string conversion you can however provide a __str__ method. This is something i personally really like.
Things I miss in ruby are:
- support for boolean value overloading
- support for overloading the function call operator
- unicode support
- slightly better threading support (at least native threads)
- native generators
- first-class methods. (I'm not talking about Proc or code blocks)
- slightly cleaner syntax
Maintainability
Say what you want but python is easier to maintain. For sure there are some libraries that are written like the developer was stoned but those are exceptions. Python doesn't support complex constructs like assignments in expressions, magic local variables like $~ and there is no implicit return value which can screw things up or make it hard to find out where exactly the return value is coming from. There is also no callcc which might be a cool thing but is hard to understand for people not using it. But there are also constructs in python that can really fuck up semantics. For example metaclasses. They are really great if you use them wisely but never try to do something with them nobody undestands.
Object System
Python and Ruby are both object orientated languages. But there are a few differences. Ruby doesn't have metaclasses and no multiple inheritance. On the other side there are special "singleton" objects which support some basic "per class" manipulation. This might be enough for ActiveRecord and other libraries to modify classes but I don't really like the idea of it because it's not clean in my eyes. Here the difference explained.
The following example shows how metaclasses in python work:
>>> class ClassOfFoo(type):
... def method_of_foo(self):
... print repr(self)
...
>>> class Foo(object):
... __metaclass__ = ClassOfFoo
...
>>> isinstance(Foo, ClassOfFoo)
True
>>> Foo.method_of_foo()
<class '__main__.Foo'>
And here the same functionallity in ruby:
irb(main):001:0> class Foo
irb(main):002:1> class << self
irb(main):003:2> def method_of_foo
irb(main):004:3> puts self.inspect
irb(main):005:3> end
irb(main):006:2> end
irb(main):007:1> end
=> nil
irb(main):008:0> Foo.method_of_foo
Foo
=> nil
But that's not the class of a class. This just modifies the singleton of a class object to add a new method. Metaclasses as such don't work, also not without syntactic sugar because you cannot subclass Class:
irb(main):009:0> class FooType < Class
irb(main):010:1> end
TypeError: can't make subclass of Class
from (irb):9
from :0
This might be only a small detail but I like it a lot and I don't want to miss it.
Regular Expressions
In Ruby 1.8 regular expressions are terrible limited. For me (who uses regular expressions in nearly every library) this is a major annoyance. fullstop.
Libraries and Webdevelopment
At least for the moment Python has the bigger library database. And even although easy_install is something I find a bit broken it's a lot better designed than gems. Especially because it doesn't require changes in the ruby libraries that use gems and it doesn't have to unpack eggs to import them. (Which is also faster)
Also webdevelopment with python makes more fun. At least for the moment. For basic CRUD stuff you can use django, for advanced applications there are hundreds of libraries and the great WSGI specs. Ruby got a WSGI clone too some time ago called Rack, but it's still not as accepted as WSGI.
Access To Internals
Python allows accessing many aspects of the interpreter core. Some of them are forwarded to python (frames via sys._getframe or tracebacks), tracebacks itself, a python compiler and parser (via the compiler package or the new _ast module). Some of them are only available via the C API. But that doesn't really matter since you can use ctypes.pythonapi to access the python C API. (Still, you don't really have to do that)
Conclusion
I hope you can now understand why I personally like Python more than ruby. But don't get me wrong. I like ruby too and I already wrote some libs for it and love to play with it. But for real applications I prefer Python.
Disclaimer: I wrote this article not to tell anybody how great python is. I don't want to tell anybody how stuipd Ruby is. And I certainly don't want to convert any Ruby developer into a Python developer! The world isn't black and white and I'm pretty sure other people have different requirements and will love Ruby more than Python.