Discussion in 'Python' started by Shi Mu, Nov 20, 2005.

1. Shi MuGuest

Got confused by the following code:
>>> a

[6, 3, 1]
>>> b

[4, 3, 1]
>>> c

{1: [[6, 3, 1], [4, 3, 1]], 2: [[6, 3, 1]]}
>>> c[2].append(b.sort())
>>> c

{1: [[6, 3, 1], [1, 3, 4]], 2: [[6, 3, 1], None]}
#why c can not append the sorted b??
>>> b.sort()
>>> b

[1, 3, 4]

Shi Mu, Nov 20, 2005

2. Guest

Shi Mu wrote:
> Got confused by the following code:
> >>> a

> [6, 3, 1]
> >>> b

> [4, 3, 1]
> >>> c

> {1: [[6, 3, 1], [4, 3, 1]], 2: [[6, 3, 1]]}
> >>> c[2].append(b.sort())
> >>> c

> {1: [[6, 3, 1], [1, 3, 4]], 2: [[6, 3, 1], None]}
> #why c can not append the sorted b??
> >>> b.sort()
> >>> b

> [1, 3, 4]

most built-in function/method don't return the "object" but None. This
I believe is the language creator's preference for everything being
explicit. You better do it like this :

b.sort()
c[2].append(b)

Of course, this make things like this not possible :

obj.method_a().method_b().method_c()

But the language(and the community) in general discourage you to write
code like this ;-)

, Nov 20, 2005

3. Eric JacoboniGuest

Shi Mu <> writes:

> #why c can not append the sorted b??

Because sort() doesn't return anything?

According to the library reference:

7) The sort() and reverse() methods modify the list in place for
economy of space when sorting or reversing a large list. To remind you
that they operate by side effect, they don't return the sorted or
reversed list.

--
Eric Jacoboni, ne il y a 1435934131 secondes

Eric Jacoboni, Nov 20, 2005
4. Magnus LyckaGuest

wrote:
> most built-in function/method don't return the "object" but None. This
> I believe is the language creator's preference for everything being
> explicit.

The list methods .sort() and .reverse() don't create copies,
but rather change the existing object. The reson for this is
to save RAM. If you have 512MB RAM and a 300 MB list, it's
nice that you can sort it without swapping virtual memory to
disk. That would slow down the sort operation a lot, and that
would be a shame, considering all the efforts that went into
Python's excellent sort implementation.

If you sort (or reverse) a list l, and don't need to keep the
unsorted list, you simply do l.sort() (or l.reverse()). If
you need to keep the original as well, you must make a copy
before the sort, like this: sorted_l = l[:]; sorted_l.sort().

If the sort operation had returned self, it would have been
easy to write:

sorted_l = l.sort()

and while sorted_l would contain what one might expect, it
would in fact just be another name referencing exactly the
same sorted list as l, and it would probably be surprising
that l was also sorted, and that subsequent changes would
show up in both sorted_l and l, and that sorted_l might not
be sorted and longer even though you only modified l. It's
this particular gotcha that the language creator wanted to
avoid.

With newer versions of Python, the builtin functions sorted()
and reversed() have been added, so those who think it's ugly
to call a list sorted before it actually *is* sorted, can
simply write:

sorted_l = sorted(l)

With older Python's you need to do the hard work to add this

def sorted(l): s=l[:];s.sort();return s
def reversed(l): r=l[:];r.reverse();return r

Actually, I guess it's possible that sorted() is done so
that it works like below, but I don't think pre-sorted()
versions of Python support keyword arguments to list.sort()
anyway...

def sorted(l, *p, **kw): s=l[:];s.sort(*p, **kw);return s

Magnus Lycka, Nov 21, 2005
5. George SakkisGuest

"Shi Mu" wrote:

> Got confused by the following code:
> >>> a

[6, 3, 1]
> >>> b

[4, 3, 1]
> >>> c

> {1: [[6, 3, 1], [4, 3, 1]], 2: [[6, 3, 1]]}
> >>> c[2].append(b.sort())
> >>> c

> {1: [[6, 3, 1], [1, 3, 4]], 2: [[6, 3, 1], None]}
> #why c can not append the sorted b??

In python 2.4, you can use the sorted() builtin instead:

c[2].append(sorted(b))

George

George Sakkis, Nov 21, 2005
6. George SakkisGuest

"Shi Mu" wrote:

> Got confused by the following code:
> >>> a

[6, 3, 1]
> >>> b

[4, 3, 1]
> >>> c

> {1: [[6, 3, 1], [4, 3, 1]], 2: [[6, 3, 1]]}
> >>> c[2].append(b.sort())
> >>> c

> {1: [[6, 3, 1], [1, 3, 4]], 2: [[6, 3, 1], None]}
> #why c can not append the sorted b??

In python 2.4, you can use the sorted() builtin instead:

c[2].append(sorted(b))

George

George Sakkis, Nov 21, 2005
7. Duncan BoothGuest

Magnus Lycka wrote:

> Actually, I guess it's possible that sorted() is done so
> that it works like below, but I don't think pre-sorted()
> versions of Python support keyword arguments to list.sort()
> anyway...
>
> def sorted(l, *p, **kw): s=l[:];s.sort(*p, **kw);return s

One part you missed, sorted is actually closer to:

def sorted(iterable, cmp=None, key=None, reverse=False):
"sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list"
s=list(iterable)
s.sort(cmp, key, reverse)
return s

The point being that while in general only a list will have a sort
method, the sorted builtin may be called on any iterable and will
return a sorted list.

Also note that it only accepts specific named arguments, and has a
docstring.

Duncan Booth, Nov 22, 2005
8. Guest

Magnus Lycka wrote:
> sorted_l = l.sort()
>
> and while sorted_l would contain what one might expect, it
> would in fact just be another name referencing exactly the
> same sorted list as l, and it would probably be surprising
> that l was also sorted, and that subsequent changes would
> show up in both sorted_l and l, and that sorted_l might not
> be sorted and longer even though you only modified l. It's
> this particular gotcha that the language creator wanted to
> avoid.
>

Since python's '=' is just name binding and that most objects(other
than those like int/float/string?) are mutable, I don't quite
understand why this is a gotcha that is so worrying.

a = [1,2,3]
a.sorted()
b = a

even an entry level python programmer can't expect 'b' to be
unchanged(after getting the first bite may be) if there is any
operation on a later. This not only applies to list but almost all
mutable object.

As you said, if one wants a copy of an object, use copy/deepcopy or
even pickle to get a snapshot of it.

, Nov 22, 2005
9. Fredrik LundhGuest

wrote:

> Since python's '=' is just name binding and that most objects(other
> than those like int/float/string?) are mutable, I don't quite
> understand why this is a gotcha that is so worrying.
>
> a = [1,2,3]
> a.sorted()
> b = a
>
> even an entry level python programmer can't expect 'b' to be
> unchanged(after getting the first bite may be) if there is any
> operation on a later. This not only applies to list but almost all
> mutable object.

so what would an entry-level Python programmer expect from this
piece of code?

for item in a.reverse():
print item
for item in a.reverse():
print item

(as the X people used to say, the only thing worse than generalizing
from one example (sort) is generalizing from no examples at all ("let's
assume I have a use case")).

</F>

Fredrik Lundh, Nov 22, 2005
10. Guest

Fredrik Lundh wrote:
> so what would an entry-level Python programmer expect from this
> piece of code?
>
> for item in a.reverse():
> print item
> for item in a.reverse():
> print item
>

I would expect it to first print a in reverse then a as it was.

a=[1,2,3]

I expect it to print

3
2
1
1
2
3

As for your other comment, I don't even understand them.

, Nov 22, 2005
11. Fredrik LundhGuest

wrote:

> > so what would an entry-level Python programmer expect from this
> > piece of code?
> >
> > for item in a.reverse():
> > print item
> > for item in a.reverse():
> > print item
> >

> I would expect it to first print a in reverse then a as it was.
>
> a=[1,2,3]
>
> I expect it to print
>
> 3
> 2
> 1
> 1
> 2
> 3

really? wouldn't

3
2
1
3
2
1

make a lot more sense ?

</F>

Fredrik Lundh, Nov 22, 2005
12. Guest

Fredrik Lundh wrote:
> wrote:
>
> > > so what would an entry-level Python programmer expect from this
> > > piece of code?
> > >
> > > for item in a.reverse():
> > > print item
> > > for item in a.reverse():
> > > print item
> > >

> > I would expect it to first print a in reverse then a as it was.
> >
> > a=[1,2,3]
> >
> > I expect it to print
> >
> > 3
> > 2
> > 1
> > 1
> > 2
> > 3

>
> really? wouldn't
>
> 3
> 2
> 1
> 3
> 2
> 1
>
> make a lot more sense ?

I have no idea. That is my expectation. I don't know yours.

My interpretation of it is :

a got reversed then I consume it one by one
a got reversed again then I consume it one by one

Because I expect a being a mutable object, anything works on it(not
just object method, but even other functions) is by default has side
effect, unless otherwise stated, like copy/deepcopy.

, Nov 22, 2005
13. Fredrik LundhGuest

wrote

> so what would an entry-level Python programmer expect from thi
> piece of code
>
> for item in a.reverse()
> print ite
> for item in a.reverse()
> print ite
>
> I would expect it to first print a in reverse then a as it was
>
> a=[1,2,3
>
> I expect it to prin
>
>
>
>
>
>
>
>

really? wouldn'

make a lot more sense

</F

Fredrik Lundh, Nov 22, 2005
14. Guest

Fredrik Lundh wrote:
> wrote:
>
> > so what would an entry-level Python programmer expect from this
> > piece of code?
> >
> > for item in a.reverse():
> > print item
> > for item in a.reverse():
> > print item
> >
> > I would expect it to first print a in reverse then a as it was.
> >
> > a=[1,2,3]
> >
> > I expect it to print
> >
> > 3
> > 2
> > 1
> > 1
> > 2
> > 3
> >

> really? wouldn't
>
> 3
> 2
> 1
> 3
> 2
> 1
>
> make a lot more sense ?

Still don't see why even you ask it again. May be you can enlight me a
bit. If this is Haskell, I would expect the result you posted.

, Nov 22, 2005
15. Fredrik LundhGuest

> Still don't see why even you ask it again.

fyi, I'm not " -spam.invalid ", and I've
never, as far I know, posted from "readfreenews.net"

</F>

Fredrik Lundh, Nov 22, 2005
16. Guest

Fredrik Lundh wrote:
> > Still don't see why even you ask it again.

>
> fyi, I'm not " -spam.invalid ", and I've
> never, as far I know, posted from "readfreenews.net"
>

I have no idea what you are talking about. I read this list through
Google's group and I saw two of the same post. Google unfortunately
just should your name "Fredrik Lundh", may be something went wrong with
the service.

, Nov 22, 2005
17. Guest

Fredrik Lundh wrote:
> wrote:
>
> > so what would an entry-level Python programmer expect from this
> > piece of code?
> >
> > for item in a.reverse():
> > print item
> > for item in a.reverse():
> > print item
> >
> > I would expect it to first print a in reverse then a as it was.
> >
> > a=[1,2,3]
> >
> > I expect it to print
> >
> > 3
> > 2
> > 1
> > 1
> > 2
> > 3
> >

> really? wouldn't
>
> 3
> 2
> 1
> 3
> 2
> 1
>
> make a lot more sense ?

I am not a complete newb at python, but I am still pretty new.
I too thought immediately that the output should be 3,2,1, 1,2,3.
I used reverse() and sort() a couple time and of course read
the docs before I did. I noted they do the change inplace, and
don't find rememering that to be a terrible burden. Actually, I
get rather annoyed by the comment that they return None "as
a reminder" that the change is inplace. How arrogant! While
I'm sure the designers had kindly intentions. my memory, though
bad, is not that bad, and I object to being forced to write code
that is more clunky than need be, because the designers thought
they needed to help me with my memory.

, Nov 22, 2005
18. OKB (not okblacke)Guest

Fredrik Lundh wrote:

> wrote:
>
>> > so what would an entry-level Python programmer expect from this
>> > piece of code?
>> >
>> > for item in a.reverse():
>> > print item
>> > for item in a.reverse():
>> > print item
>> >

>> I would expect it to first print a in reverse then a as it was.
>>
>> a=[1,2,3]
>>
>> I expect it to print
>>
>> 3
>> 2
>> 1
>> 1
>> 2
>> 3

>
> really? wouldn't
>
> 3
> 2
> 1
> 3
> 2
> 1
>
> make a lot more sense ?

Yes. The unintuitive thing is that the list is sorted in place at
all.

--
--OKB (not okblacke)
Brendan Barnwell
no path, and leave a trail."
--author unknown

OKB (not okblacke), Nov 22, 2005
19. Steven D'ApranoGuest

On Tue, 22 Nov 2005 08:53:07 -0800, rurpy wrote:

> I am not a complete newb at python, but I am still pretty new.
> I too thought immediately that the output should be 3,2,1, 1,2,3.

What you are saying is that a.reverse() should *both* change a in place
*and* return a reference to the same list.

> I used reverse() and sort() a couple time and of course read
> the docs before I did. I noted they do the change inplace, and
> don't find rememering that to be a terrible burden. Actually, I
> get rather annoyed by the comment that they return None "as
> a reminder" that the change is inplace. How arrogant! While
> I'm sure the designers had kindly intentions. my memory, though
> bad, is not that bad, and I object to being forced to write code
> that is more clunky than need be, because the designers thought
> they needed to help me with my memory.

Built-in methods with side-effects (sort, reverse, update, clear, etc.)
return None because every function must return something, not because it
is a reminder. Python is not Pascal, and there are no procedures.

There are four possibilities for a construction like list.sort():

(1) sort the list in place and return a reference to the same list;
(2) sort the list in place and return a copy of the same list;
(3) sort the list in place and return None;
(4) don't sort in place and return a sorted list.

No solution is always right, no solution is always wrong, but the most
flexible is a combination of (3) and (4). Python now has that with sort()
and sorted(). Prior to the addition of sorted() to the language, (3) was
considered the best solution because of a simple Python principle: never
duplicate objects unless explicitly told to.

--
Steven.

Steven D'Aprano, Nov 22, 2005
20. Guest

Steven D'Aprano wrote:
> There are four possibilities for a construction like list.sort():
>
> (1) sort the list in place and return a reference to the same list;
> (2) sort the list in place and return a copy of the same list;
> (3) sort the list in place and return None;
> (4) don't sort in place and return a sorted list.
>
> No solution is always right, no solution is always wrong, but the most
> flexible is a combination of (3) and (4). Python now has that with sort()
> and sorted(). Prior to the addition of sorted() to the language, (3) was
> considered the best solution because of a simple Python principle: never
> duplicate objects unless explicitly told to.
>

I don't see the reason that (3) and (4) are the most flexible.

Again, "never duplicate objects unless explicitly told to" combined
with "=" is name binding gives me a very strong message that
list.sort() it will change things in place and which is why it is quite
natural(for me at least)

3
2
1
1
2
3

for this language. Wether it is "best" or make more sense doesn't
really matter to me, though I am curious to know why.

But basically, I just use the language as it is, and the way I want to.
So long it solves my problem and gives me the result I want.

, Nov 22, 2005