A few more Python thoughts from a Perl guy

So recently I’ve been playing around with the Python, even bought a book to make things slightly less haphazard. First I want to get it out of the way, I like programming in Python – more than Ruby when I dabbled in it (surprisingly, to me, actually) and much more than any time spent with PHP.

Fundamentally, I think there’s a vast philosophical difference between Perl and Python which I need to internalize and will spare me much frustration. Perl comes from a culture and evolutionary standpoint of Do What I Mean. Perl tries to let you type in some stuff and it does generally what you probably mean to do. I think this bothers some people. Python programmers probably, because although as far as I know they haven’t encodified this the way Perl has DWIM, Python is a Do What I Say kind of language. You need to be pretty explicit with it. I don’t think there’s a right or wrong in this argument, just a philosophical difference.

Now on to saying stuff.

The indenting thing, I’m totally cool with it. In fact sometimes when I’m doing perl and things get a little hairy with a few adjacent close parens, I’m like, huh, that looks messy. On the other hand, I really, really like being able to put my cursor on a paren and shift-5 to have my cursor jump to its mate (you know, Vim style). That’s really useful.

Something really bothers me, though. I’ve read a few times in the book where they’ve built in a feature with one of its implementation goals to discourage the use of that feature. What? This is totally stupid, either implement the feature full on because you need it and it is a good idea or don’t because you don’t believe in it. For example, the ternary operator, well beloved by this developer. In other languages with it, they’ve cribbed the C version – in Perl for example:

$is_zombie = undead() ? 'yes' : 'grr. argh.';

but in Python they have to say:

is_zombie = 'yes' if undead() else 'grr. argh.'

And the reason for this change of syntax? Quoted from the footnote:

This was reportedly done in response to analysis of common use patterns in Python code, but also partially to discourage ex-C programmers from overusing it!

I mean, that’s literally the dumbest thing I’ve ever heard. Ok. Not literally. But it’s dumb. There’s nothing wrong with the ternary operator it’s very easy to understand once you know what it means and it’s a concise efficient way to code a lot of things.

Another example of this is Python’s hobbled lambda functions. Anonymous functions are very useful, you can easily make them and pass them around without worrying about naming and all that extra typing. But in Python these functions are limited to exactly one expression. That’s right. The function can consist of one expression. What? Why?

Because it is limited to an expression, a lambda is less general than a def—you can only squeeze so much logic into a lambda body without using statements such as if. This is by design—it limits program nesting: lambda is designed for coding simple functions, and def handles larger tasks.

Oh. This is what I mean when I talk of holier than thou languages. Languages that tell you exactly how you should be programming. Right after that in the same section of the book the author tells you how to cheat this by using list comprehensions and what not to get more complicated logic into the lambdas, presumably because it is often good to do so, but then says you should worry about obfuscating your code. Of course, because the language forces you to do so to use this construct, these hacks increase the obfuscation of the code. Great job.

They also have a lot of that inverted loop/branching logic like the ternary operator – but only for special cases. Another example is in their list comprehensions where you can say something like:

squared_nums = [ x**2 for Range(5) ]

Which is nice and concise. By why not offer that syntax outside of list comprehensions? I mean, it’s just nice to be able to say things like:

continue if test_something()
sys.stdout.write(line) for line in open('file')

That is, though, just the Perl developer in me talking.

In general I like developing in Python, as is obvious, I miss things from Perl (*cough*labeled blocks*cough*block scope*cough*) but I’m enjoying switching my mode of thinking. Learning new languages is always good and makes you better at programming in general and it’s been awhile since I’ve really had a go at it. I guess I have Google and App Engine to thank for that (although App Engine itself isn’t without it’s frustrations for me! Again, I suspect a mindset change is required).

  • This may be interesting to you

  • Savvu

    The comment on discouraging the use features is just the opinion of the author of the book. It may be shared by some other people in the Python community but that still does not make it the "true" rationale behind these decisions!

    A lambda function is a value. You can embed it anywhere in the middle of an expression, in nested parentheses, etc. Just try to design your own syntax for Python lambdas that allows multiple statements, ifs, fors, etc and you will quickly realize why it was done the way it is. It would require an alternative syntax for blocks that uses something other than indentation. It's not like someone has gone out of his way to discourage people from building more complex lambda functions. It was simply considered not worth the effort to invent a convoluted new syntax for it which would not be very pythonic. The alternative (write a local function and pass its name) is probably more readable, anyway, for anything longer than fits comfortably in a short lambda. It's not a value judgement - just a pragmatic choice.

    The same is true for the trinary operator. Any other syntax would not be consistent with Python's syntax which is based on keywords, not magical runes. Python, unlike javascript and some other languages, does not assume the programmer necessarily has previous knowledge of C. You can understand Python's trinary operator the first time you encounter it without any explanations. It only looks strange to you because it's different from your C experience.

    You can safely ignore this kind of silly opinions about discouraging the use of features. Outside of a few minor warts which are being removed in Python 3.0 everything in Python is meant to be used and enjoyed.

    Python is not "holier than thou". It simply doesn't go out of its way to provide multiple ways of doing the same thing when one is enough.

  • dude

    There's a major downside to this approach, though:

    x = ( callMeIfFalse(), callMeIfTrue() )[ condition ]

    both functions get called, and the value for x is chosen from the constructed tuple (since false evaluates to the 0th element of the tuple and true evaluates to the 1st). So you can't decide behavior using this method wheras you could do (in Ruby, but it's nearly identical in perl):

    x = condition ? callMeIfTrue() : callMeIfFalse()

  • JS

    The Python ternary operator was added because of the widespread use of and/or in the language before it was created. See for example the description provided in Dive into Python: http://www.diveintopython.org/...

    Compared to that sort of construct, X if Y else Z is much cleaner to use.

  • I use the and/or construct regularly, but you have to watch out because it doesn't work in all cases:

    >>> True and 0 or 42

  • Just to be clear, though, that's not a true ternary operator since it relies on the "truth" of 'yes' position. The Python ternary is that undead() if 'yes' else 'grr. argh.' - I was just noting that it's an odd construction and if its purpose was (as printed in the book) to discourage use, well, I don't appreciate that in language design. It isn't a big deal, really, I mean, the if/else construction is obvious and concise, it's just the philosophy behind doing it that way that I was commenting on.

    Also, I talk about Python's anonymous functions above... I just kind of dislike that they're hobbled. As Hans suggests, this may be a limitation of significant white space syntax - I still dislike it. :)

  • numix

    You can easily replicate ternary functionality using tuples then the conditional to select the appropriate one. e.g.
    >>> ("b", "a")[True]
    >>> ("b", "a")[False]
    Sure it's backwards, but it's rather easy to understand.
    If you want it to read like a typical ternary, you can do 'cond and "a" or "b" ' to achieve the same result.
    >>> True and "a" or "b"
    >>> False and "a" or "b"

  • random guy

    Python does actually have a ternary, but it looks different from a c ternary:

    $is_zombie = undead() ? 'yes' : 'grr. argh.';
    is_zombie = undead() and 'yes' or 'grr. argh.'

    And obviously, python does have anonymous functions as another commentor pointed out

  • Hmm, the reason lambdas are crippled is because it's awkward (to say the least) to have an indentation-based function body inside an expression. If you write a multi-line function, you might as well just use def, anyway.

    I wasn't aware that these features are "discouraged"... first time I hear about it. I must say that Python's ternary operator is really ugly, though. I avoid it whenever possible.

  • llimllib

    Sam, I replied to you but the disqus comments thingy got freaked out when I typed the wrong password. Look below.

  • llimllib

    That's a nested function, not an anonymous one.

    (btw, I'm a pythonista who has a day job writing Ruby, and much prefers python's cleanliness to Ruby's "do whatever you want, it'll probably maybe work" philosophy. I think there's a switch in each developer's head that's flipped one way or the other.)

  • Well, you can always use os.popen...

  • Python has anonymous functions as well.


    def foo():
    def bar():
    # ... Do something complicated

    map([1,2,3], bar)

  • Heh, personally I don't mind the absence of do/while. Python does have the while/else and for/else loops, which are somewhat interesting. I think it's all just a difference in philosophy where Python's is much more prescriptive (than Perl's say, but I think everyone's philosophy - except maybe PHP's - is more prescriptive than Perl's :), which can be beneficial to many. Diff'rent strokes for diff'rent folks. That's what I heard at least. ;)

  • z

    Python doesn't even have a do {} while construct. Seriously, this language has been "designed" by a nazi.

  • Peter, while I don't necessarily have a problem with the verbosity above, I think readability is in the eye of the reader. That is, you can optimize readability for a novice or you can optimize it for a reasonably experienced developer, in my opinion I prefer to optimize it for someone who knows how to develop. As a developer it's much quicker for me to see and understand 2>&1 than a few long name value pairs.

    In that vein perl allows you to say use English which then turns a lot of short hand variables into long human readoable ones. I've never come across any because Perl devs simply understand what the short hand is so they are readable.

    Obviously, that can be taken too far and things can become obfuscated if shorthand becomes too clever, but in general, I think a little programmer friendly shorthand is a good thing.

  • Peter

    > ^ i mean wtf?!

    The concept is called "readability". Great thing.

  • t35t0r

    I agree. I'm a perl guy and started learning python and the first thing that really annoyed me is it's verbosity. Open a pipe:

    open($myPipe, "command 2>&1|");
    subprocess.Popen("command", shell=true, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    subprocess.Popen("command", shell=true, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]

    ^ i mean wtf?!

  • dude, I'll definitely be revisiting Ruby. I need to work a couple more App Engine apps out of my system, though. I liked Ruby, too, as a language I quite enjoyed it. I believe most of my frustrating moments were ones wrangling Rails.

  • dude

    err, ARE present in Ruby, eg. your gripes AREN'T present, the stuff you want is :P

  • dude

    You should really take another look at Ruby. You can almost write straight python in it, except it's borrowed heavily from perl and not 'ABC'. next if condition, and many of your other gripes are not present in ruby.

blog comments powered by Disqus

Not Found

Sorry, but what you are looking for isn't here...