There's actually a reason for each of the three methods you listed, specific to each project.
- Bottle tries to keep things as
simple/straightforward as possible
for the programmer. With decorators
for routes you don't have to worry
about the developer understanding OOP.
- Pylons development goal is to make
code re-usable and to be easily
integrated with WSGI-style HTTP
process routing. As such, they have
chosen a very OOP way of organizing
routes. As an example, you could
copy & paste HelloController into any
Pylons app and it should just
magically work. Even if said app is
being served up via WSGI in some
complicated fashion.
- Tornado has yet another reason for
doing things the way it does:
Tornado's epoll-based IOLoop (in conjunction with tornado.web.Application)
instantiates each RequestHandler as
requests come in. By keeping each
RequestHandler limited to a specific
GET or POST this allows IOLoop to
quickly instantiate the class,
process the request, and finally let
it get garbage collected. This keeps
it fast and efficient with a small
memory footprint regardless of how
many RequestHandlers your application
has. This is also the reason why Tornado can handle so many more simultaneous requests than other Python-based web servers (each request gets its own instance).
Now, having said all that you should know that you can always override the default framework behavior. For example, I wrote a MethodDispatcher for Tornado that makes it work more like Pylons (well, I had CherryPy in mind when I wrote it). It slows down Tornado a tiny amount (and increases the memory footprint slightly) due to having one large RequestHandler (as opposed to a lot of small ones) but it can reduce the amount of code in your app and make it a little easier to read (In my biased opinion, of course =).