It all sounds Geek to me! [Gautam Arora]

Thursday, August 11, 2005

Lets be more Pythonic ...

This is C:

for (i=0; i < class="entryText">
   do_something(mylist[i]);
}
--------------------------------------
Is this being Pythonic:

i = 0
while i < mylist_length:
do_something(mylist[i])
i += 1
NO! certainly not!
--------------------------------------
Then this must be being Pythonic:
for i in range(mylist_length):
do_something(mylist[i])

Nopes!
--------------------------------------
This one ?
for element in mylist:
do_something(element)
Oh Yes! This is is more like it!
--------------------------------------

"To be Pythonic is to use the Python constructs and
datastructures with clean, readable idioms.
It is Pythonic is to exploit dynamic typingfor instance,
and it's definitely not Pythonic to introducestatic-type style
verbosity into the picture where not needed. To bePythonic is
to avoid surprising experienced Python programmers with unfamiliar
ways to accomplish a task."

--------------------------------------
This is a must-try for anyone with a python interpreter around.
Invoke the python interpreter and type 'import this'.

C:\>python
Python 2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>>
--------------------------------------
The Pythonic way of getting the Python source code:

import ftplib

f=ftplib.FTP("ftp.python.org")
f.login()
f.cwd("pub/python/2.4/")
f.retrbinary("RETR Python-2.4.tar.bz2",open('Python-2.4.tar.bz2','wb').write)
f.quit()

This code works(try it if you have a python interpreter)!
--------------------------------------

Additional info at:
Python Secret Weblog - Martijn Faassen's musings
and Python Corner-Linux For You(LFY)

10 comments:

Nadeem Mohsin said...

Yeah - it's always really painful when you apply the idioms of one language to another. This isn't just limited to computer languages - try checking out a Hindi movie with English subtitles - all the jokes fall flat...

BTW, if do_something() returns another element, then you could just go:

ret = [do_something(elem) for elem in li]

Man, I love list comprehensions...

I've been a fan of the Zen of Python thing for ages now...I remember once sending it to Thite. Perfect Python style - make it good, make it clear, make it fun. No wonder the guys at Google love it...

And the other nice thing is that bad behaviour is discouraged, but not explicitly prohibited - this is really useful if you wanna defy a few conventions for the sake of a cleaner solution.

Nadeem Mohsin said...

For people not familiar with list comprehensions, that little code snippet will apply do_something() to every element in li, and store the result in another list called ret...

Hmmm - just remembered you might be able to use the map() function too. There's another one liner for you...

BTW, you might wanna post something on map(), reduce() and filter() - you can really do some fancy stuff with those once you get the hang of them. Plus it's a good place to use lambda functions...

I remember reading somewhere that Guido Van Rossum wants to eliminate lambda functions in a future version of Python. Haven't had a chance to look it up - know anything about this?

Gautam Arora said...

For all those who want to get to know more about what Nadeem has been talking about, try cracking Py Chal Level 2,
and you will witness the power of list comprehensions.
I will try to post something about the stuff you mentioned. map() again reminds me of level 2, seems you havent forgotten it either :)

Maverick said...

Well, iv heard ppl say that py code is more readable than ruby, it mite be true, but once u get used to ruby, EVERYTHING doesnt else doesnt seem quite as good! As they say, Ruby does spoil u! wont say more here, will just give code examples...

for the code in the blog, the equivalent code in ruby is

li.each {|elem| elem.do_somthing}

as for "list comprehensions", its such a piece of cake in ruby, i dont even think they have such a term :P

ret = li.each {|elem| elem.do_somthing}

this is where i think ruby scores over py, cuz the code remains essentially the same. As ruby is totally OO, everything DOES return a value (usually of the last statement executed unless an explicit return statement) so its basically upto us, whether we wanna use the value or not!!! :D

oc, code readability is a very subjective thing, and i feel ruby code is more readble, atleast in this case. But the undeniable fact is, using code blocks with iterators is a lot more powerful than py! (for the uninitiated, 'each' is an iterator which returns each element of the array, the thing followed by it is the code block in {} brackets).

well, the debate continues...hehe

Gautam Arora said...

Python: [do_something(elem) for elem in li]
Ruby: li.each {|elem| elem.do_something}

With the Py code above, a list is returned with [None,None,...] even if you do not return anything and it depends on you if you want to use it like this,

Python: ret=[do_something(elem) for elem in li]
Ruby: ret=li.each {|elem| elem.do_something}

As for the 'each' iterator, its very much here in py too:
Python: [do_something(elem) for each in li]

Readability is most certainly a subjective issue, and if both camps say that both are readable, then i think its true.
Comparing the code lines above: Ruby looks a little cryptic(thats coz i havent read even an intro to ruby) and just by being true-OO doesnt give u more power(not saying that you dont have any)

On one side ruby syntax looks cryptic and on the other hand, it tries to be simple to understand as everything is OO...why cant we have a lil less cryptic and a lil less OO.....ah, did i say python...i think thats where py score over ruby :P

the debate continues.....

Hrishikesh said...

Blocks and iterators in Ruby are just not limited to one liners. They can do a lot more... Am really on a serious shortage of time here, and so have kind of left of my Ruby pursuit here, but one day, I'll send along many examples.

AFAIK, there is no equivalent to yield in Python. Only Ruby has it. Now, one may argue, programs have been written and will continue to be written without it. Fine. Keep using square wheels, and then don't blame us if we win the race by using round ones!

Hrishikesh said...

And yes, round wheels ARE difficult to make than the square ones, but only till the system of making them round isn't perfected. Once that is done, the square wheel is left far behind.

Gautam Arora said...

Well, this certainly is turning out to be a py vs ry debate and will not cease....
I just have one ques for the ruby guys...
how do you display a 'Hello World' in ruby.....
>print 'Hello World'
but why not print.'Hello World' or 'Hello World'.print()....
where did u forget ur true-OO...should i say there is much to fix in ur round wheel!

What surprises me how you consider that one feature makes a difference from round wheels to square ones...do u think that one feature makes and breaks a language?
the post was just based on python, and never meant to be a battleground with ruby... :)

If you consider python to be running on square wheels or for that matter any other mature language like Java,PHP etc and say, that ruby is the one with the round wheels.....u leave me speechless for being so ignorant!

If a newer language is always gonna have an extra 'killer' feature then u mite as well wait for another language in the pipeline...
Python has many years of development behind it, and thats one of its 'killer' features too.No one here denies the momentum gained by Ruby in recent times, but that certainly aint enough to say that ya its gonna leave everyone behind it...

p.s. i love the indentation too!

Nadeem Mohsin said...

Man, I missed all the fun. Ah well, let battle be joined!

Hrishikesh said...

As for Ruby not being OO enough...

print (and also gets and puts) is a class method (also known as static methods in other programming languages) of the Ruby kernel class. Now, you can most certainly call kernel::print("Hello world!") or kernel::print "Hello world!". The whole point is that since the kernel is Ruby itself, and you are in the kernel, you need not explicitily reference it. Nothing stops you from doing it anyway.

Hope this makes the post above moot.