Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > [newbie] A question about lists and strings

Reply
Thread Tools

[newbie] A question about lists and strings

 
 
Mok-Kong Shen
Guest
Posts: n/a
 
      08-10-2012

In an earlier question about lists, I was told about the issue of
creation of local names in a function. However, I still can't
understand why the program below outputs:

[999] sss
[999]

and not two identical lines of output. For both operators "+=" should
anyway work in similar manner in the function xx in my view.

Thanks for your help in advance.

M. K. Shen

----------------------------------------------------------

def xx(list,str):
list+=[999]
str+="sss"

lista=[]
stra=""
lista+=[999]
stra+="sss"
print(lista,stra)

listb=[]
strb=""
xx(listb,strb)
print(listb,strb)
 
Reply With Quote
 
 
 
 
Roman Vashkevich
Guest
Posts: n/a
 
      08-10-2012
10.08.2012, Χ 13:19, Mok-Kong Shen ΞΑΠΙΣΑΜ(Α):

>
> In an earlier question about lists, I was told about the issue of
> creation of local names in a function. However, I still can't
> understand why the program below outputs:
>
> [999] sss
> [999]
>
> and not two identical lines of output. For both operators "+=" should
> anyway work in similar manner in the function xx in my view.
>
> Thanks for your help in advance.
>
> M. K. Shen
>
> ----------------------------------------------------------
>
> def xx(list,str):
> list+=[999]
> str+="sss"
>
> lista=[]
> stra=""
> lista+=[999]
> stra+="sss"
> print(lista,stra)
>
> listb=[]
> strb=""
> xx(listb,strb)
> print(listb,strb)
> --
> http://mail.python.org/mailman/listinfo/python-list


It seems like your xx() function doesn't return local str parameter and prints the global empty str, whereas it mutates the global list.

Roman
 
Reply With Quote
 
 
 
 
Roman Vashkevich
Guest
Posts: n/a
 
      08-10-2012

10.08.2012, Χ 13:28, Roman Vashkevich ΞΑΠΙΣΑΜ(Α):

> 10.08.2012, Χ 13:19, Mok-Kong Shen ΞΑΠΙΣΑΜ(Α):
>
>>
>> In an earlier question about lists, I was told about the issue of
>> creation of local names in a function. However, I still can't
>> understand why the program below outputs:
>>
>> [999] sss
>> [999]
>>
>> and not two identical lines of output. For both operators "+=" should
>> anyway work in similar manner in the function xx in my view.
>>
>> Thanks for your help in advance.
>>
>> M. K. Shen
>>
>> ----------------------------------------------------------
>>
>> def xx(list,str):
>> list+=[999]
>> str+="sss"
>>
>> lista=[]
>> stra=""
>> lista+=[999]
>> stra+="sss"
>> print(lista,stra)
>>
>> listb=[]
>> strb=""
>> xx(listb,strb)
>> print(listb,strb)
>> --
>> http://mail.python.org/mailman/listinfo/python-list

>
> It seems like your xx() function doesn't return local str parameter and prints the global empty str, whereas it mutates the global list.
>
> Roman


Excuse me for the mess I just did in my message
The function doesn't print anything of cause. It takes list by reference and creates a new local str.
When it's called with listb and strb arguments, listb is passed by reference and mutated. A string "sss" is concatenated with an empty local str. Nothing more happens. Since local str is not returned by xx(), it can not be expected to be printed out in the statement that follows. What is printed out in the print statement is the mutated listb and the global strb.

RV
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      08-10-2012
Mok-Kong Shen wrote:

>
> In an earlier question about lists, I was told about the issue of
> creation of local names in a function. However, I still can't
> understand why the program below outputs:
>
> [999] sss
> [999]
>
> and not two identical lines of output. For both operators "+=" should
> anyway work in similar manner in the function xx in my view.
>
> Thanks for your help in advance.
>
> M. K. Shen
>
> ----------------------------------------------------------
>
> def xx(list,str):
> list+=[999]
> str+="sss"


a += b

is internally translated into to

a = a.__iadd__(b)

If the 'list' class were implemented in Python it would look like

class list:
def __iadd__(self, other):
for item in other:
self.append(item)
return self

i. e. the original list is modified when you perform += and you'll see the
modification when you look at any name bound to that original list:

b = a = [1, 2]
a += [3, 4]
print a # [1, 2, 3, 4]
print b # [1, 2, 3, 4]

Strings on the other hand are "immutable" -- they cannot be altered after
the initial creation. The hypothetical __iadd__() implementation is

class str:
def __iadd__(self, other):
return self + other

So += rebinds a name to a new string:

b = a = "first"
a += "second"
print b # first
print a # firstsecond

Armed with this knowledge

> lista=[]
> stra=""
> lista+=[999]


[999] is appended to lista and lista is rebound to itself.

> stra+="sss"


A new string "" + "sss" is created and stra is bound to that new string.

> print(lista,stra)



> listb=[]
> strb=""
> xx(listb,strb)


Inside xx()

(1) 999 is appended to listb and the local variable list is rebound.
(2) A new string "" + "sss" is created and bound to the local variable str.

> print(listb,strb)


If you have understood the above here's a little brain teaser:

>>> a = ([1,2,3],)
>>> a[0] += [4, 5]

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

>>> a[0]


What are the contents of a[0] now?


 
Reply With Quote
 
Dave Angel
Guest
Posts: n/a
 
      08-10-2012
On 08/10/2012 05:19 AM, Mok-Kong Shen wrote:
>
> In an earlier question about lists, I was told about the issue of
> creation of local names in a function. However, I still can't
> understand why the program below outputs:
>
> [999] sss
> [999]
>
> and not two identical lines of output. For both operators "+=" should
> anyway work in similar manner in the function xx in my view.
>
> Thanks for your help in advance.
>
> M. K. Shen
>
> ----------------------------------------------------------
>
> def xx(list,str):
> list+=[999]
> str+="sss"
>
> lista=[]
> stra=""
> lista+=[999]
> stra+="sss"
> print(lista,stra)
>
> listb=[]
> strb=""
> xx(listb,strb)
> print(listb,strb)


I'm rewriting your xx function so it doesn't overwrite reserved words,
list and str.

def xx(mylist, mystring):
mylist += [999]
mystring += "xxx"

There are a couple of effects you need to understand in order to see
what's happening.

First, some terminology. You don't assign values in Python, you bind a
name or another lvalue to an object. a=650 builds an object of type
int, and binds it to the name a. if you then say b=a, you bind b to the
*SAME* object, the previously created int object of value 650. It can
be useful to print the id() of an object, to convince yourself that
they're actually the same. So if you print id(a) and id(b), you'll get
the same value. But if you said c=651 and d=651, you'd have two
objects, and the two names would be bound to different objects, with
different ids.

The += operator is an example of an augmented assignment operator.
Others that behave the same way include *= -= and so on.

The += operator tries to modify the object referred to by the left hand
side, by modifying that object in place. If that fails, perhaps because
the object is immutable, then it builds a new object, and binds the left
side to that new object.

So, if you have a list, and you use += to append to it, you still have
the same list object, but it's longer now. If you have a string, or an
int, or ... that's immutable, then it builds a new one, and binds it to
the left side.

Now, put those two operations inside a function, and what do we have ?
Let's go through the function, looking at what happens.

Local parameter mylist gets bound to the list object bound to listb.
The object is not copied, it's now bound to new names, one in the global
space, one local. When the mylist += statement is executed, it
modifies that object, and instantly the global "variable" listb is modified.

Local parameter mystring gets bound to the string object bound to strb.
We still only have one (immutable) object. When the mystring +=
statement is executed, it creates a new string object by concatenating
the old one and the "xxx" string. At this point, we can print
id(mystring) and see that it changed. When the function returns, the
local symbols are unbound, and the new string object is discarded since
there are no longer any refs.

At this point, in top-level code, the listb object has been modified,
and the strb one has not; it still is bound to the old value.



--

DaveA

 
Reply With Quote
 
Mok-Kong Shen
Guest
Posts: n/a
 
      08-10-2012
Am 10.08.2012 12:07, schrieb Dave Angel:
[snip]
> At this point, in top-level code, the listb object has been modified,
> and the strb one has not; it still is bound to the old value.


This means there is no way of modifying a string at the top level
via a function, excepting through returning a new value and assigning
that to the string name at the top level. Please again correct me, if
I am wrong.

M. K. Shen

 
Reply With Quote
 
Chris Angelico
Guest
Posts: n/a
 
      08-10-2012
On Fri, Aug 10, 2012 at 8:12 PM, Mok-Kong Shen
<(E-Mail Removed)> wrote:
> Thanks for the explanation of the output obtained. But this means
> nonetheless that parameters of types lists and strings are dealt with
> in "inherently" (semantically) different ways by Python, right?


It's nothing to do with parameters, but yes, lists are mutable and
strings are immutable. A tuple will behave the same way a string does:

>>> a

(1, 2, 3, 4)
>>> b=a
>>> a+=5, # note that "5," is a one-element tuple
>>> a

(1, 2, 3, 4, 5)
>>> b

(1, 2, 3, 4)


By the way:

On Fri, Aug 10, 2012 at 8:07 PM, Dave Angel <(E-Mail Removed)> wrote:
> But if you said c=651 and d=651, you'd have two
> objects, and the two names would be bound to different objects, with
> different ids.


To be more accurate, you *may* have two different objects. It's
possible for things to be optimized (eg with small numbers, or with
constants compiled at the same time).

ChrisA
 
Reply With Quote
 
Dave Angel
Guest
Posts: n/a
 
      08-10-2012
On 08/10/2012 06:12 AM, Mok-Kong Shen wrote:
> Am 10.08.2012 11:48, schrieb Roman Vashkevich:
>> [snip]
> >The function .... It takes list by reference and creates a new local
> > str. When it's called with listb and strb arguments, listb is passed
> > by reference and mutated. A string "sss" is concatenated with an
> > empty local str. Nothing more happens. Since local str is not
> > returned by xx(), it can not be expected to be printed out in the
> > statement that follows. What is printed out in the print statement is
> > the mutated listb and the global strb.

>
> Thanks for the explanation of the output obtained. But this means
> nonetheless that parameters of types lists and strings are dealt with
> in "inherently" (semantically) different ways by Python, right?
>
> M. K. Shen
>


Nothing to do with parameters. Lists are mutable, and strings are
immutable, so += behaves differently.



--

DaveA

 
Reply With Quote
 
Chris Angelico
Guest
Posts: n/a
 
      08-10-2012
On Fri, Aug 10, 2012 at 8:31 PM, Mok-Kong Shen
<(E-Mail Removed)> wrote:
> This means there is no way of modifying a string at the top level
> via a function, excepting through returning a new value and assigning
> that to the string name at the top level. Please again correct me, if
> I am wrong.


Yes, but you can (ab)use a one-element list as a pointer.

>>> foo=["Hello"]
>>> def mutate(ptr):

ptr[0]="World"

>>> mutate(foo)
>>> print(foo[0])

World

But it's probably worth thinking about exactly why you're wanting to
change that string, and what you're really looking to accomplish.
There may well be a better way.

Chris Angelico
 
Reply With Quote
 
Mok-Kong Shen
Guest
Posts: n/a
 
      08-10-2012
Am 10.08.2012 12:40, schrieb Chris Angelico:

> But it's probably worth thinking about exactly why you're wanting to
> change that string, and what you're really looking to accomplish.
> There may well be a better way.


My problem is the following: I have at top level 3 lists and 3 strings:
lista, listb, listc and stra, strb, strc. I can with a single function
call change all 3 list values. How could I realize similar changes
of the 3 string values with a single function call?

Thanks in advance.

M. K. Shen


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Determining lists,strings and numbers(Newbie question) vimal Ruby 3 06-28-2008 07:03 PM
Re: Lists of lists and tuples, and finding things within them Daniel Nogradi Python 3 11-10-2006 07:57 AM
Strings, Strings and Damned Strings Ben C Programming 14 06-24-2006 05:09 AM
List of lists of lists of lists... =?UTF-8?B?w4FuZ2VsIEd1dGnDqXJyZXogUm9kcsOtZ3Vleg==?= Python 5 05-15-2006 11:47 AM
converting lists to strings to lists robin Python 10 04-12-2006 04:58 PM



Advertisments