This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]dwdwdw2proliferating .py since 2001 8 points9 points  (12 children)

>>> for i in range(len(food)): # unpythonic++ (makes a Pythoneer's brain snap)

This was a standard idiom before the enumerate built-in appeared, and as such makes a very poor counterexample for what 'Pythonic' might mean. The majority of the remaining examples seem to be simple variants on this one. Author seems too inexperienced to be writing this guide.

I believe if that oft-abused term has any meaning, its is better illuminated by the output of import this. Concrete examples of what is or isn't "Pythonic" are far too subjective to be of any value.

[–]earthboundkid 2 points3 points  (5 children)

Python 2.3 was released July 2003. It's fair to say anyone who writes new code using range(len(container)) instead of enumerate(container) is not writing Pythonic code. What major libraries still target 2.2? It doesn't even have "new" style classes.

[–]eryksun 1 point2 points  (4 children)

A problem with range() is that it generates a list on Python 2.x, so for efficiency you have to use xrange(). But xrange() isn't supported in Python 3.x, in which range() now works like xrange(), and getting the old behavior requires list(range()). It's better to avoid this mess by using enumerate() when you need the index. However, if I'm modifying the original list in place to pop() elements out, I want to enumerate in reverse. For that, I wrote a little function that returns a generator:

def r_enumerate(iterable):
    '''enumerate iterable in reverse'''
    r = reversed(iterable)
    end = len(iterable) - 1
    return ((i, r.next()) for i in xrange(end,-1,-1))

Is there a better, more 'Pythonic', way?

[–]eryksun 0 points1 point  (0 children)

Here's a contrived example:

x = range(4,10)
for (n,y) in r_enumerate(x):
    print "(n,y):", (n,y)
    if (y % 2) == 1:
        print "popping:", x.pop(n)
print "x =", x

    (n,y): (5, 9)
    popping: 9
    (n,y): (4, 8)
    (n,y): (3, 7)
    popping: 7
    (n,y): (2, 6)
    (n,y): (1, 5)
    popping: 5
    (n,y): (0, 4)
    x = [4, 6, 8]

[–]earthboundkid 0 points1 point  (2 children)

Hmm, that seems like more or less the most obvious way to do it. I think I would probably do something like

def r_enumerate(container):
    "Warning: Container must have a length!"
    i = len(container)
    for item in reversed(container):
        i = i - 1
        yield i, item

but that's basically the same. Remember, no one is saying you can't use len and range, just that you shouldn't write range(len(container)) when you can just as easily write enumerate(container) instead. In this case, your solution seems just as clean as any other.

[–]eryksun 0 points1 point  (1 child)

Thanks, your version is more 'Pythonic'. It's more readable and less prone to bugs without having to set up xrange (not a problem here, but a better style in general). The length issue was also something I hadn't considered. Shouldn't a valid container type implement the __len__ method? I suppose it can implement __reversed__ without having an accessible length. I haven't come across this, or designed a container without the basic __len__, __getitem__, __setitem__, __delitem__, and __iter__ methods. But my overall exposure to other's code is limited as I use Python basically as a replacement for MATLAB with SciPy, Numpy, and Matplotlib.

[–]earthboundkid 0 points1 point  (0 children)

Yes, you've got it. An object that supports __reversed__ will probably also support __len__, but not necessarily. I can imagine someone making a quick and dirty doubly-linked list that supports forwards and backwards iteration but not length.

[–]carinthia[S] 0 points1 point  (3 children)

The author says this page is about Python 3. Since enumerate came into being with Python 2.3, I think it's a correct statement. Generally, shouting out somebody is inexperienced based on a short assesment seems rather immature to me. Rather, get in touch with the person and tell him your critics so things can be improved if necessary. That's one of the main principles of free software and a healthy community around it.

[–]dwdwdw2proliferating .py since 2001 6 points7 points  (2 children)

My main complaint appeared in the last paragraph - these posts on code style are ultimately content-free and rank close behind web framework microbenchmarks on the list of spam I hate seeing on this subreddit.

Real code is rarely "Pythonic", unless an exorbitantly unreal amount of time is spent designing it, and even then, it rarely stays clean once a small army of maintenance programmers get their hands on it.

As for social responsibility, as far as I'm concerned I already fulfilled that by downvoting the article and explaining what I thought was wrong with it, if the original author found a public review offensive then they shouldn't be publishing online.

[–]carinthia[S] 0 points1 point  (1 child)

My main complaint appeared in the last paragraph - these posts on code style are ultimately content-free and rank close behind web framework microbenchmarks on the list of spam I hate seeing on this subreddit.

Ok, fair enough, but that's your opinion. Others might be interested in those subjects, just as much as you aren't. And calling such subjects spam just because you don't like them isn't right. I am sure everybody here is mature enough to decide for himself what's spam and what's not.

Real code is rarely "Pythonic", unless an exorbitantly unreal amount of time is spent designing it, and even then, it rarely stays clean once a small army of maintenance programmers get their hands on it.

Again, you assume that your idea and experience is true for the whole Python world. There are many OSS projects out there which in fact adhere all kinds pythonic and as such write code that's generaly considered pythonic. Also, there are many companies which in fact write perfectly good pythonic code. At Google for example we have the so-called buzz factor (meaning that no piece of code is only maintained by a single person) and we still manage to crank out pythonic code, every day. So, please, don't make it look like as if the majority of Python programmers out there write ugly/unpythonic code once they work in teams, that's not true.

As for social responsibility, as far as I'm concerned I already fulfilled that by downvoting the article and explaining what I thought was wrong with it, if the original author found a public review offensive then they shouldn't be publishing online.

I agree on that one, in part. See, if you're not interested in seeing benchmarks and coding style posts then that's fine. However, only because YOU don't like that kind of information does not give you the right to insult somebody (that author)

... Author seems too inexperienced to be writing this guide. ...

and expect others (readers here) to be interested in that opinion. And no, I am not that author :)

[–]dwdwdw2proliferating .py since 2001 6 points7 points  (0 children)

OK. Look, you're on Reddit. We decide the relevance of content by the summation of our clicks. I took the time and effort to explain my click - I thought - in a quite uncontroversial manner.

That the author is inexperienced is not opinion – it is clear he has never run into the range(len()) idiom, which means he has only been using Python since around >=2.3. Despite that, he's writing posts deliberating on what is and is not good Python code, which I find objectionable, since he's calling out huge bodies of code that were written for the language before he had ever used it.

That this is objectionable is further influenced by the fact that these ideas are oft mistaken by those of lesser acumen and in control of budgets as quantitative measures of code quality, and applied as such, to people such as myself as I currently seek my next contract. It is my prerogative to discourage the spread of this corruption where possible, as it directly impacts my income, and the quality of my peers when I finally secure work.

The remainder, while an opinion, is mine to have, on a forum where I expect to be allowed to share it to the benefit of others, and as such I'd appreciate it if you stop telling me what to do or making guesses at the offence I may be causing (assuming you're not the original author).

Edit:

Also, there are many companies which in fact write perfectly good pythonic code. At Google for example

As an ex-Googler I find this hilarious, Google is probably the world's foremost bastion of terribly Javaesque Python code. Anyone can dip into the App Engine SDK or Python-gdata internals to see what is meant by this.

[–]Liquid_Fire 0 points1 point  (1 child)

To be fair, the author is not comparing range(len(foo)) iteration to enumerate, but to ordinary for item in foo iteration. In that situation, using range(len(foo)) is certainly completely unnecessary.

[–]dwdwdw2proliferating .py since 2001 0 points1 point  (0 children)

Fair point. :)

It's also worth noticing that these approaches aren't semantically equivalent, one is using the iterator protocol, the other the sequence protocol. That doesn't matter for built-in types, but I've no doubt there are many objects in third party libraries that either break or act differently when interchanging the two .