22

Is the following code bad practice?

for i in some_values:
    do_whatever(i)
do_more_things(i)

Somehow, it feels to me like the variable i should remain in the scope to the block inside the for-loop. However python 2.7 lets me reuse it after the loop.

Does python officially supports that feature, or am I abusing the language?

Niriel
  • 2,605
  • 3
  • 29
  • 36
  • hmmm... seems like this might be ok since it is used [here](http://stackoverflow.com/questions/2138873/cleanest-way-to-get-last-item-from-python-iterator) – jamylak May 12 '12 at 12:23
  • 1
    There are a fair number of use-cases which benefit from accessing the last value of a loop variable in subsequent code – Mike Pennington May 12 '12 at 12:28

5 Answers5

19

Yes, it's official:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

> The target list is not deleted when the loop is finished 

http://docs.python.org/reference/compound_stmts.html#for

Note that a target list after for is far more than just a variable:

for some_list[blah] in...
for some_object.foo in...
for a[:n] in ...:

etc. These things cannot simply disappear after the loop.

georg
  • 211,518
  • 52
  • 313
  • 390
7

Python can feel a bit special when it comes to scoping if you are coming from languages like C or Java. As previous answer says, the code is absolutely valid but I would recommend against it. It creates not particularly readable code and, furthermore, if some_values turns out to be empty, there will be an exception raised on the last line of the code.

So answer to your question is - yes, it is officially supported but in most cases it is not recommended strategy.

Interesting discussion can be found here and also local discussion on SO.

Community
  • 1
  • 1
petr
  • 2,554
  • 3
  • 20
  • 29
  • Who doesn't recommend it? And why would it make the code difficult to read - python variables exist throughout their scope, however they are introduced. – Marcin May 12 '12 at 12:29
  • I agree. It just feels "dirty". – georg May 12 '12 at 12:36
  • 2
    First of all, I believe it makes an assumption that the loop is ran and the variable indeed assigned. Secondly, when reading this as a third-person, I would assume the variables defined on the same/lower indent. But python community is divided on this one. – petr May 12 '12 at 12:44
  • "I would assume the variables defined on the same/lower indent" Why would you assume that? – Marcin May 12 '12 at 12:46
  • @Marcin I am sorry - I cannot quote any rule on that. This stems from my personal experience. As I have clarified - the python community is a bit divided on this one and I would be up for loops having their own scope. But I suppose I may be a minority on that one :) – petr May 12 '12 at 12:50
  • @petr My point is that your assumption is not valid because the language explicitly allows the contrary to occur. – Marcin May 12 '12 at 12:53
  • @Marcin I can agree on my point not being particularly strong but I would be reluctant to do so based on your argument - the language allows many things which are not considered very good code, for example, it is even possible to implement a [GOTO](http://entrian.com/goto/)! And there is not much of an argument about that being a good practise.. I suppose a good counter-argument to mine would be stating that there is could be a good reason to use such construct. – petr May 12 '12 at 16:44
  • @petr There's a substantial body of opinion (you can find the discussions on old SO questions) that goto is appropriate in certain circumstances. In any case, the module you refer to implements a thrid-party language extension - it tells us nothing about whether or not that is a good practice. – Marcin May 12 '12 at 18:15
  • @Marcin Yes but it is still recommended to be avoided in majority of cases. Regarding the module I have shown - I was simply making a point that not everything allowed by the language, either out of the box or via extension, is not automatically a good practice - I am sure I could find many other examples not using any extensions. Either way, Thank you very much for the exchange here - I believe we should stop the comment stream as the question itself has been answered well enough. – petr May 14 '12 at 15:00
  • @petr An example involving a language extension is meaningless. You can conjure any extension you like. As to whether or not something is good practice, that is entirely orthogonal to whether or not you should expect it. – Marcin May 14 '12 at 15:05
5

You can use this technique to scan a list for items matching some criteria:

for item in iter:
    if interesting(item):
        break
else:
    raise ValueError('iter is boring.')

handle(item)
Ben Millwood
  • 6,754
  • 24
  • 45
1

Just like @petr said, it sound unnatural. Not because it's allowed that it's natural or you have to use it.

I rather have something like this, although it may not apply to the logic with a break use-case:

for i in some_values:
    do_whatever(i)
else:
    do_more_things(i)

But this still raise NameError if some_values evaluate to empty, but sounds clearer. It does not give the clear readability of an inner scope but the indentation may suggests it.

But as other said, to answer to the specific OP's question, yes, it's legal.

Danosaure
  • 3,578
  • 4
  • 26
  • 41
-1

That's not a feature. As you wrote the variable remains in the scope. It's normal interpreter behavior.

Maksym Polshcha
  • 18,030
  • 8
  • 52
  • 77
  • 3
    Hmm, I downvoted this because "That's not a feature" seems to directly contradict the top answer, but now re-reading the question I think you mean "it's not a feature that `i` only lasts for the loop scope" which is true. I'm going to leave the downvote there though, because I think your wording is unclear and the interpretation I first had was the more natural one (and wrong). – Ben Millwood May 12 '12 at 16:36