Many newbie questions regarding python

  • Thread starter Rogério Brito
  • Start date
E

Ethan Furman

Steven said:
And how often do you have an list that you are creating where you don't
know what items you have to initialise the list with?
[snip]

You are right to point out that the third case is a Python gotcha: [[]]*n
doesn't behave as expected by the naive or inexperienced Python
programmer. I should have mentioned it, and pointed out that in that case
you do want a list comp [[] for i in range(n)].

But that doesn't mean that the list comp is the general purpose solution.
Consider the obvious use of the idiom:

def func(arg, count):
# Initialise the list.
L = [arg for i in range(count)]
# Do something with it.
process(L, some_function)

def process(L, f):
# Do something with each element.
for item in enumerate(L):
f(item)

Looks good, right? But it isn't, because it will suffer the exact same
surprising behaviour if f modifies the items in place. Using a list comp
doesn't save you if you don't know what the object is.

I've only been using Python for a couple years on a part-time basis, so
I am not aquainted with this obvious use -- could you give a more
concrete example? Also, I do not see what the list comp has to do with
the problem in process() -- the list has already been created at that
point, so how is it the list comp's fault?

~Ethan~
 
P

Peter Pearson

Steven D'Aprano wrote: [snip]
But that doesn't mean that the list comp is the general purpose solution.
Consider the obvious use of the idiom:

def func(arg, count):
# Initialise the list.
L = [arg for i in range(count)]
# Do something with it.
process(L, some_function)

def process(L, f):
# Do something with each element.
for item in enumerate(L):
f(item)

Looks good, right? But it isn't, because it will suffer the exact same
surprising behaviour if f modifies the items in place. Using a list comp
doesn't save you if you don't know what the object is.

I've only been using Python for a couple years on a part-time basis, so
I am not aquainted with this obvious use -- could you give a more
concrete example? Also, I do not see what the list comp has to do with
the problem in process() -- the list has already been created at that
point, so how is it the list comp's fault?

Well, here's a worked example of Steven D's code (Python 2.5.2):
.... L = [arg for i in range(count)]
.... process(L, some_function)
.... .... for item in L:
.... v(item)
.... .... x.append(1)
.... print x
....
[1]
[1, 1]
[1, 1, 1]
Is that the output you expected? Probably not: the unwary
reader (including me, not too long ago) expects that

L = [arg for i in range(count)]

will be equivalent to

L = [[], [], []]

but it's not, because the three elements in the first L are three
references to the *same* list. Observe:
arg = []
L = [arg for i in range(3)]
L [[], [], []]
L[0].append(1)
L
[[1], [1], [1]]

.... as opposed to ...
L = [ [] for i in range(3)]
L [[], [], []]
L[0].append(1)
L
[[1], [], []]
 
E

Ethan Furman

Peter said:
Steven D'Aprano wrote:
[snip]
But that doesn't mean that the list comp is the general purpose solution.
Consider the obvious use of the idiom:

def func(arg, count):
# Initialise the list.
L = [arg for i in range(count)]
# Do something with it.
process(L, some_function)

def process(L, f):
# Do something with each element.
for item in enumerate(L):
f(item)

Looks good, right? But it isn't, because it will suffer the exact same
surprising behaviour if f modifies the items in place. Using a list comp
doesn't save you if you don't know what the object is.

I've only been using Python for a couple years on a part-time basis, so
I am not aquainted with this obvious use -- could you give a more
concrete example? Also, I do not see what the list comp has to do with
the problem in process() -- the list has already been created at that
point, so how is it the list comp's fault?


Well,

the unwary
reader (including me, not too long ago) expects that

L = [arg for i in range(count)]

will be equivalent to

L = [[], [], []]

but it's not, because the three elements in the first L are three
references to the *same* list. Observe:

<snip>

My question is more along the lines of: a mutable object was passed in
to func()... what style of loop could be used to turn that one object
into /n/ distinct objects? A list comp won't do it, but neither will a
for loop, nor a while loop.

Further, Steven stated "it will suffer the exact same surprising
behaviour if f modifies the items in place" -- the damage has already
been done by that point, as L has however many copies of the *same* object.

Seems to me you would have to use copy.copy or copy.deepcopy to be safe
in such a circumstance, and the loop style is irrelevant.

If I've missed something, somebody please enlighten me.

~Ethan~
 
J

Jean-Michel Pichavant

Peter said:
Steven D'Aprano wrote:
[snip]
But that doesn't mean that the list comp is the general purpose solution.
Consider the obvious use of the idiom:

def func(arg, count):
# Initialise the list.
L = [arg for i in range(count)]
# Do something with it.
process(L, some_function)

def process(L, f):
# Do something with each element.
for item in enumerate(L):
f(item)

Looks good, right? But it isn't, because it will suffer the exact same
surprising behaviour if f modifies the items in place. Using a list comp
doesn't save you if you don't know what the object is.
I've only been using Python for a couple years on a part-time basis, so
I am not aquainted with this obvious use -- could you give a more
concrete example? Also, I do not see what the list comp has to do with
the problem in process() -- the list has already been created at that
point, so how is it the list comp's fault?

Well, here's a worked example of Steven D's code (Python 2.5.2):

... L = [arg for i in range(count)]
... process(L, some_function)
...
... for item in L:
... v(item)
...
... x.append(1)
... print x
...
[1]
[1, 1]
[1, 1, 1]


Is that the output you expected? Probably not: the unwary
reader (including me, not too long ago) expects that

L = [arg for i in range(count)]

will be equivalent to

L = [[], [], []]

but it's not, because the three elements in the first L are three
references to the *same* list. Observe:

arg = []
L = [arg for i in range(3)]
L
[[], [], []]
[[1], [1], [1]]

... as opposed to ...

L = [ [] for i in range(3)]
L
[[], [], []]
[[1], [], []]
After that many replies and dozen of solutions I wonder if the OP is
puzzeled or satisfied. Just saying ... :D

JM
 
P

Peter Pearson

My question is more along the lines of: a mutable object was passed in
to func()... what style of loop could be used to turn that one object
into /n/ distinct objects? A list comp won't do it, but neither will a
for loop, nor a while loop.

Ah. Quite right. So, Yes, what you want is more objects that
in some sense are copies of the original object. This is getting
way over my head, because there are situations in which it's
hard to say what would constitute a copy of an object, such as
when the object in question is a chat session with a specific
interlocutor.
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top