A question on modification of a list via a function invocation

Cameron Simpson cs at cskk.id.au
Wed Aug 16 21:44:43 EDT 2017


On 17Aug2017 02:49, Mok-Kong Shen <mok-kong.shen at t-online.de> wrote:
>I don't yet understand. Why (by which rule of the language reference)
>should "alist=[30,60,90]" mean discarding the name's reference to the
>[1,2,3] list?

Section 7.2: Simple statements: Assignment Statements.

It says:

  An assignment statement evaluates the expression list (remember that this can 
  be a single expression or a comma-separated list, the latter yielding a 
  tuple) and assigns the single resulting object to each of the target lists, 
  from left to right.

So this:

  alist=[30,60,90]

"evaluates the expression list" (that is the [30,60,90]) and assigns it.

So this creates a new list object [30,60,90]. This is independent of whatever 
is/was in "alist". Then the reference to that is assigned to the name "alist".  
Since a name references to a single object, necessarily the reference to what 
"alist" previously refered is discarded.

So before this statement, both "ss" and "alist" referered to the list [1,2,3].  
After the statement "ss" has not been changed, and still refers to the [1,2,3] 
list. But "alist" now points to the new list which was created by the right 
hand side of the assignment statement i.e. the new [30,60,90] list.

You might try inserting some print statements in your code. 

  print("ss = %s:%r, alist = %s:%r" % (id(ss), ss, id(alist), alist))

after every statement in your code to see these changes. The id() function 
returns Python's internal object id for each existing object - this is unique 
at any given time. If two names refer to the same object, the same id will be 
printed. So this will let you see directly when the names start pointing at 
different objects.

You can also go:

  print("alist[0] = %s:%r" % (id(alist[0]), alist[0]))

to see the internal things within lists and so forth.

>What I conjecture is that in test2 the assignment
>"alist[0], ..." can only have a proper meaning according to the syntacs
>of Python if alist is meant to be the global alist.

There is no "global alist".

>But then, since
>now the name alist is known to be global, why then in the next line of
>test2 the name is suddenly interpreted to be local?

There are two reasons for this. Firstly, "alist" is a function parameter.  That 
is a local name, always. Also, every python function definition is inspected 
for assignment statements.  Any assignment statement "x = ..." causes the name 
"x" to be a local variable. This is important, because it provided _reliable_ 
and predictable behaviour.

>(Which rule of
>the language reference says that?) That's what I currently continue to
>wonder.

4.2. Naming and Binding.

4.2.1 starts "Names refer to objects. Names are introduced by name binding 
operations.  The following constructs bind names: formal parameters to 
functions, ...". So a function parameter is a name binding.

Then "if a name is bound in a block, it is a local variable of that block, 
unless declared as nonlocal or global." ("nonlocal" and "global" are explicit 
statements.) So a function parameter, which is a binding, causes that name to 
be local to the function.

Regarding the inspection side of things to which i alluded to earlier, under 
"4.2.2. Resolution of names" it says "If a name binding operation occurs 
anywhere within a code block, all uses of the name within the block are treated 
as references to the current block. This can lead to errors when a name is used 
within a block before it is bound. This rule is subtle. Python lacks 
declarations and allows name binding operations to occur anywhere within a code 
block. The local variables of a code block can be determined by scanning the 
entire text of the block for name binding operations."

Cheers,
Cameron Simpson <cs at cskk.id.au> (formerly cs at zip.com.au)



More information about the Python-list mailing list