for loop without variable

T

Torsten Bronger

Hallöchen!

Torsten said:
[...]

Right, that's because I've used "__" where not all returning
values are interesing to me such as

a, b, __ = function_that_returns_three_values(x, y)

Variable name "dummy" serves the same purpose, such as:

a, b, dummy = function_that_returns_three_values(x, y)

Granted, but my rationale is that "__" is less visible in the source
code, so there is more emphasis on the actually interesting
variables.

Tschö,
Torsten.
 
G

Guest

Torsten said:
Torsten said:
[...]

Right, that's because I've used "__" where not all returning
values are interesing to me such as

a, b, __ = function_that_returns_three_values(x, y)

Variable name "dummy" serves the same purpose, such as:

a, b, dummy = function_that_returns_three_values(x, y)

Granted, but my rationale is that "__" is less visible in the source
code, so there is more emphasis on the actually interesting
variables.

I guess it's a matter of preference. Personally, I find "dummy" to be more
explicit, and hence more readable for those that that will read my code
later. YMMV.

Regards,
..david
 
M

Mike Meyer

It depends how the code is written. In the example such as:

for meaningless_variable in xrange(number_of_attempts):
...

the loop variable really has no meaning. Rewriting this code only to
appease pylint is exactly that, it has nothing with making the code
more readable.

Except in this case, the variable *has* a meaning. You've just chosen
to obfuscate it.
you've hidden that meaning by giving it the meaningless name "i". If
you give it a meaningful name, then there's an obvious way to do it
(which you listed yourself):

while retries_left:
[...]

This loop contains more code and hence more opportunities for
introducing bugs. For example, if you use "continue" anywhere in the
loop, you will do one retry too much.

All correct - and I'm a big fan of minimizing code, as code you don't
write has no bugs in it. But you can still show the meaning of this
"meaningless" variable:

for number_of_attempts in xrange(maximum_attempts):

Of course, the OP's request is a better solution: since he doesn't
actually need the variable, removing it completely means there's one
less variable, which is one less thing you can set to the wrong value.

<mike
 
B

Basilisk96

erik gartz said:
The loop performs some actions with web services. The particular
iteration I'm on isn't important to me. It is only important that I
attempt the web services that number of times. If I succeed I
obviously break out of the loop and the containing function (the
function which has the loop in it) returns True. If all attempts
fail the containing loop returns False.

When you have iteration requirements that don't seem to fit the
built-in types (lists, dicts, generators etc.), turn to 'itertools'
... import random
... print "Trying ..."
... success = random.choice([True, False])
... return success
...... if foo_attempt():
... break
...
Trying ...
Trying ...
Trying ...
Trying ...
Trying ...
Trying ...
Note that this is possibly more readable than 'for foo_attempt in
[foo] * max_attempts", and is more efficient for large values of
'max_attempts' because 'repeat' returns an iterator instead of
actually allocating the whole sequence.
I guess based on the replies of everyone my best bet is to leave the
code the way it is and suck up the warning from pylint.

I think your intent -- "repeat this operation N times" -- is better
expressed by the above code, than by keeping count of something you
don't actually care about.
I don't want to turn the warning off because catching unused
variables in the general is useful to me.

Agreed.

--
\ "Dyslexia means never having to say that you're ysror." |
`\ --anonymous |
_o__) |
Ben Finney

Neat! That is the best solution I've seen so far. I should definitely
dig into the itertools module more often.

Cheers,
-Basilisk96
 
M

Marty

Hrvoje said:
Mike Meyer said:
It sounds to me like your counter variable actually has meaning,

It depends how the code is written. In the example such as:

for meaningless_variable in xrange(number_of_attempts):
...

the loop variable really has no meaning. Rewriting this code only to
appease pylint is exactly that, it has nothing with making the code
more readable.
you've hidden that meaning by giving it the meaningless name "i". If
you give it a meaningful name, then there's an obvious way to do it
(which you listed yourself):

while retries_left:
[...]

This loop contains more code and hence more opportunities for
introducing bugs. For example, if you use "continue" anywhere in the
loop, you will do one retry too much.

I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

This caused me to wonder why Python does not have a "foreach" statement (and
also why has it not come up in this thread)? I realize the topic has probably
been beaten to death in earlier thread(s), but does anyone have the short answer?
 
R

Ryan Ginstrom

On Behalf Of Marty
I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

This caused me to wonder why Python does not have a "foreach"
statement (and also why has it not come up in this thread)?
I realize the topic has probably been beaten to death in
earlier thread(s), but does anyone have the short answer?

data_out = [[] for item in data_in]

Regards,
Ryan Ginstrom
 
M

Mike Meyer

I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

More succinctly:

data_out = []
for _ in data_in:
data_out.append([])

Or, as has already been pointed out:

data_out = [[] for _ in data_in]
This caused me to wonder why Python does not have a "foreach" statement (and
also why has it not come up in this thread)? I realize the topic has probably
been beaten to death in earlier thread(s), but does anyone have the short answer?

But I'm curious - what's the difference between the "foreach" you have
in mind and the standard python "for"?

<mike
 
M

Matimus

It depends how the code is written. In the example such as:
for meaningless_variable in xrange(number_of_attempts):
...
the loop variable really has no meaning. Rewriting this code only to
appease pylint is exactly that, it has nothing with making the code
more readable.
you've hidden that meaning by giving it the meaningless name "i". If
you give it a meaningful name, then there's an obvious way to do it
(which you listed yourself):
while retries_left: [...]

This loop contains more code and hence more opportunities for
introducing bugs. For example, if you use "continue" anywhere in the
loop, you will do one retry too much.

I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

This caused me to wonder why Python does not have a "foreach" statement (and
also why has it not come up in this thread)? I realize the topic has probably
been beaten to death in earlier thread(s), but does anyone have the short answer?

Pythons `for' essentially is foreach. The code below does the same
thing as what you have posted does. Actually, I've found that if you
find yourself ever doing range(len(data_in)) in python, it is time to
take a second look.

data_out = []
for x in data_in:
data_out.append([])

`range' is just a function that returns a list.

Matt
 
P

Paul Rubin

erik gartz said:
The loop performs some actions with web services. The particular
iteration I'm on isn't important to me. It is only important that I
attempt the web services that number of times. If I succeed I
obviously break out of the loop and the containing function (the
function which has the loop in it) returns True. If all attempts fail
the containing loop returns False.

This uses an index var, but doesn't leak it outside the genexp, so
I don't know what pylint would say (untested):

def f():
return any(attempt_service() for i in xrange(10))

I think the above is pretty natural. If you really insist on not
using any variables, the below might work (untested):

from itertools import imap, repeat

def f():
return any(imap(apply, repeat(attempt_service, 10)))

it just seems way too obscure though. Python style seems to favor
spewing extra variables around.
 
P

Paul Rubin

Mike Meyer said:
data_out = [[] for _ in data_in]
...
But I'm curious - what's the difference between the "foreach" you have
in mind and the standard python "for"?

The "for" loop, like the list comprehension, pollutes the namespace
with an index variable that's not used for anything. I prefer genexps:

data_out = list([] for x in data_in)
 
C

Carl Banks

I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

This caused me to wonder why Python does not have a "foreach" statement
(and also why has it not come up in this thread)? I realize the topic
has probably been beaten to death in earlier thread(s), but does anyone
have the short answer?

Most languages that have "foreach" use it the same way Python uses
"for". The reason they use "foreach" instead of plain "for" is often
because they have a separate for statement that mimic C's for.

Perhaps you're wondering why there is no syntax for looping a given
number of times. (Languages that have this feature, e.g., Ada, often to
use "repeat" as the keyword.)

1. Looping a fixed number of times is quite uncommon.
2. A syntax for it buys you almost nothing.


Carl Banks
 
M

Marty

Mike said:
I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

More succinctly:

data_out = []
for _ in data_in:
data_out.append([])

Or, as has already been pointed out:

data_out = [[] for _ in data_in]

That's nice.
But I'm curious - what's the difference between the "foreach" you have
in mind and the standard python "for"?

<mike

For example, I thought the python "equivalent" of perl's foreach might be:

data_out = [[] foreach data_in]

Trying to answer my own question, if it comes down to a choice between a unique
statement v. the anonymous variable "_", then I guess I can see why Python did
it this way.
 
B

Basilisk96

It depends how the code is written. In the example such as:
for meaningless_variable in xrange(number_of_attempts):
...
the loop variable really has no meaning. Rewriting this code only to
appease pylint is exactly that, it has nothing with making the code
more readable.
you've hidden that meaning by giving it the meaningless name "i". If
you give it a meaningful name, then there's an obvious way to do it
(which you listed yourself):
while retries_left: [...]

This loop contains more code and hence more opportunities for
introducing bugs. For example, if you use "continue" anywhere in the
loop, you will do one retry too much.

I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

This caused me to wonder why Python does not have a "foreach" statement (and
also why has it not come up in this thread)? I realize the topic has probably
been beaten to death in earlier thread(s), but does anyone have the short answer?

But it does:

data_in = (1,2,3,4,5)
data_out = []

data_out += [[] for blah in data_in]

print data_out
[[], [], [], [], []]


Cheers,
-Basilisk96
 
M

Mike Meyer

For example, I thought the python "equivalent" of perl's foreach might be:


No, python's equivalent of Perl's foreach is "for". I.e.

foreach $var (@list)

does the same thing as Python's

for var in list

(except Perl gets the scoping right).

Maybe you're thinking of Perls "default variable" feature (I don't
know what else to call it), which implicitly uses $_ as a variable in
any number of places if you fail to provide a variable? So that you
can say:

foreach (@list)

and apparently not have to use a variable, except it implicitly uses $_.

<mike
 
F

Fredrik Lundh

Paul said:
it just seems way too obscure though. Python style seems to favor
spewing extra variables around.

that's because (local) variables have near-zero cost, and zero overhead.
use as many as you want, and reuse them as often as you want to.

(and if you use sane naming conventions, the risk for collisions is near
zero as well).

</F>
 
P

Paul Rubin

Fredrik Lundh said:
(and if you use sane naming conventions, the risk for collisions is
near zero as well).

I haven't felt that way, I'm always worried about clobbering something
by leaking a variable. Maybe collisions don't really happen much, but
it's always seemed cleaner to me to use the most restricted scopes
possible just to minimize or eliminate the possibility. This is
especially attractie in a language like Python, with no declarations
and no compile-time type safety.
 
N

Neil Hodgson

Marty:
I recently faced a similar issue doing something like this:

data_out = []
for i in range(len(data_in)):
data_out.append([])

Another way to write this is
data_out = [[]] * len(data_in)

Neil
 
M

Mike Meyer

Marty:
I recently faced a similar issue doing something like this:
data_out = []
for i in range(len(data_in)):
data_out.append([])

Another way to write this is
data_out = [[]] * len(data_in)

Not quite. All the other variants give you 23 empty lists. That one
gives you 23 references to one list:
x = [[] for _ in range(23)]
x[1].append(23)
x [[], [23], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]
x = [[]] * 23
x[1].append(23)
x
[[23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23], [23]]


<mike
 
T

Tim Chase

I recently faced a similar issue doing something like this:
data_out = []
for i in range(len(data_in)):
data_out.append([])

Another way to write this is
data_out = [[]] * len(data_in)

....if you're willing to put up with this side-effect:
data_in = range(10)
data_out = [[]] * len(data_in)
data_out [[], [], [], [], [], [], [], [], [], []]
data_out[0].append('hello')
data_out
[['hello'], ['hello'], ['hello'], ['hello'], ['hello'],
['hello'], ['hello'], ['hello'], ['hello'], ['hello']]

For less flakey results:
data_out = [[] for _ in data_in]
data_out [[], [], [], [], [], [], [], [], [], []]
data_out[0].append('hello')
data_out
[['hello'], [], [], [], [], [], [], [], [], []]


-tkc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top