Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #6521 > unrolled thread

scope of function parameters

Started byHenry Olders <henry.olders@mcgill.ca>
First post2011-05-29 04:30 -0400
Last post2011-05-31 10:33 -0700
Articles 20 on this page of 27 — 14 participants

Back to article view | Back to comp.lang.python


Contents

  scope of function parameters Henry Olders <henry.olders@mcgill.ca> - 2011-05-29 04:30 -0400
    Re: scope of function parameters Mel <mwilson@the-wire.com> - 2011-05-29 07:59 -0400
      Re: scope of function parameters Terry Reedy <tjreedy@udel.edu> - 2011-05-29 16:27 -0400
    Re: scope of function parameters Peter Pearson <ppearson@nowhere.invalid> - 2011-05-29 17:21 +0000
      Re: scope of function parameters Ben Finney <ben+python@benfinney.id.au> - 2011-05-30 07:42 +1000
        Re: scope of function parameters Laurent Claessens <moky.math@gmail.com> - 2011-05-30 09:12 +0200
          Re: scope of function parameters Chris Rebert <clp2@rebertia.com> - 2011-05-30 00:27 -0700
          Re: scope of function parameters Laurent <moky.math@gmail.com> - 2011-05-30 09:38 +0200
          Re: scope of function parameters Daniel Kluev <dan.kluev@gmail.com> - 2011-05-30 19:10 +1100
          Re: scope of function parameters Terry Reedy <tjreedy@udel.edu> - 2011-05-30 05:02 -0400
            Re: scope of function parameters Laurent Claessens <moky.math@gmail.com> - 2011-05-30 11:08 +0200
              Re: scope of function parameters Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-05-30 09:14 +0000
              Re: scope of function parameters Ben Finney <ben+python@benfinney.id.au> - 2011-05-30 19:17 +1000
              Re: scope of function parameters Peter Otten <__peter__@web.de> - 2011-05-30 11:41 +0200
                Re: scope of function parameters Laurent Claessens <moky.math@gmail.com> - 2011-05-30 12:10 +0200
                Re: scope of function parameters Laurent Claessens <moky.math@gmail.com> - 2011-05-30 12:10 +0200
              Re: scope of function parameters Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-05-30 13:40 +0300
              Re: scope of function parameters Terry Reedy <tjreedy@udel.edu> - 2011-05-30 12:49 -0400
          Re: scope of function parameters Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-05-30 09:16 +0000
    Re: scope of function parameters Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-05-29 23:46 +0000
      Re: scope of function parameters Ben Finney <ben+python@benfinney.id.au> - 2011-05-30 11:31 +1000
        Re: scope of function parameters Chris Angelico <rosuav@gmail.com> - 2011-05-30 11:56 +1000
          Re: scope of function parameters Ben Finney <ben+python@benfinney.id.au> - 2011-05-30 12:08 +1000
            Re: scope of function parameters Chris Angelico <rosuav@gmail.com> - 2011-05-30 12:37 +1000
        Re: scope of function parameters Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-05-30 04:23 +0000
    Re: scope of function parameters rusi <rustompmody@gmail.com> - 2011-05-31 09:46 -0700
      Re: scope of function parameters rusi <rustompmody@gmail.com> - 2011-05-31 10:33 -0700

Page 1 of 2  [1] 2  Next page →


#6521 — scope of function parameters

FromHenry Olders <henry.olders@mcgill.ca>
Date2011-05-29 04:30 -0400
Subjectscope of function parameters
Message-ID<mailman.2216.1306661462.9059.python-list@python.org>
I just spent a considerable amount of time and effort debugging a program. The made-up code snippet below illustrates the problem I encountered:

def main():
	a = ['a list','with','three elements']
	print a
	print fnc1(a)
	print a
	
def fnc1(b):
	return fnc2(b)

def fnc2(c):
	c[1] = 'having'
	return c

This is the output:
['a list', 'with', 'three elements']
['a list', 'having', 'three elements']
['a list', 'having', 'three elements']

I had expected the third print statement to give the same output as the first, but variable a had been changed by changing variable c in fnc2.

It seems that in Python, a variable inside a function is global unless it's assigned. This rule has apparently been adopted in order to reduce clutter by not having to have global declarations all over the place.

I would have thought that a function parameter would automatically be considered local to the function. It doesn't make sense to me to pass a global to a function as a parameter.

One workaround is to call a function with a copy of the list, eg in fnc1 I would have the statement "return fnc2(b[:]". But this seems ugly.

Are there others who feel as I do that a function parameter should always be local to the function? Or am I missing something here?

Henry



[toc] | [next] | [standalone]


#6530

FromMel <mwilson@the-wire.com>
Date2011-05-29 07:59 -0400
Message-ID<irtce4$19b$1@speranza.aioe.org>
In reply to#6521
Henry Olders wrote:

> I just spent a considerable amount of time and effort debugging a program.
> The made-up code snippet below illustrates the problem I encountered:
> 
> def main():
> a = ['a list','with','three elements']
> print a
> print fnc1(a)
> print a
> 
> def fnc1(b):
> return fnc2(b)
> 
> def fnc2(c):
> c[1] = 'having'
> return c
> 
> This is the output:
> ['a list', 'with', 'three elements']
> ['a list', 'having', 'three elements']
> ['a list', 'having', 'three elements']
> 
> I had expected the third print statement to give the same output as the
> first, but variable a had been changed by changing variable c in fnc2.
> 
> It seems that in Python, a variable inside a function is global unless
> it's assigned. This rule has apparently been adopted in order to reduce
> clutter by not having to have global declarations all over the place.
> 
> I would have thought that a function parameter would automatically be
> considered local to the function. It doesn't make sense to me to pass a
> global to a function as a parameter.

It doesn't look like a question of local or global.  fnc2 is passed a 
container object and replaces item 1 in that container.  You see the results 
when fnc2 prints the object it knows as `c`, and you see again when main 
prints the object it knows as `a`.  Python doesn't pass parameters by 
handing around copies that can be thought of as local or global.  Python 
passes parameters by binding objects to names in the callee's namespace.  In 
your program the list known as `a` in main is identically the same list as 
the one known as `c` in fnc2, and what happens happens.

	Mel.

[toc] | [prev] | [next] | [standalone]


#6570

FromTerry Reedy <tjreedy@udel.edu>
Date2011-05-29 16:27 -0400
Message-ID<mailman.2238.1306700850.9059.python-list@python.org>
In reply to#6530
On 5/29/2011 7:59 AM, Mel wrote:
> Henry Olders wrote:
>
>> I just spent a considerable amount of time and effort debugging a program.
>> The made-up code snippet below illustrates the problem I encountered:
>>
>> def main():
>> a = ['a list','with','three elements']
>> print a
>> print fnc1(a)
>> print a
>>
>> def fnc1(b):
>> return fnc2(b)
>>
>> def fnc2(c):
>> c[1] = 'having'
>> return c
>>
>> This is the output:
>> ['a list', 'with', 'three elements']
>> ['a list', 'having', 'three elements']
>> ['a list', 'having', 'three elements']
>>
>> I had expected the third print statement to give the same output as the
>> first, but variable a had been changed by changing variable c in fnc2.
>>
>> It seems that in Python, a variable inside a function is global unless
>> it's assigned. This rule has apparently been adopted in order to reduce
>> clutter by not having to have global declarations all over the place.
>>
>> I would have thought that a function parameter would automatically be
>> considered local to the function.

Function *parameters* are names, the first *local names* of the function.

>> It doesn't make sense to me to pass a global to a function as a parameter.

You are right, in a way;-). Global *names* are just names. When you call 
a function, you pass *objects* as *arguments*. Of course, you may refer 
to the object by a global name to pass it, or you can pass a string 
object that contains a global name.
>
> It doesn't look like a question of local or global. fnc2 is passed a
> container object and replaces item 1 in that container.  You see the results
> when fnc2 prints the object it knows as `c`, and you see again when main
> prints the object it knows as `a`.  Python doesn't pass parameters by
> handing around copies that can be thought of as local or global.  Python
> passes parameters by binding objects to names in the callee's namespace.  In
> your program the list known as `a` in main is identically the same list as
> the one known as `c` in fnc2, and what happens happens.

Right. Python has one unnamed 'objectspace'. It has many, many 
namespaces: builtins, globals for each module, locals for each function 
and class, and attributes for some instances. Each name and each 
collection slot is associated with one object. Each object can have 
multiple associations, as in the example above.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#6551

FromPeter Pearson <ppearson@nowhere.invalid>
Date2011-05-29 17:21 +0000
Message-ID<94fdk7FihlU1@mid.individual.net>
In reply to#6521
On Sun, 29 May 2011 04:30:52 -0400, Henry Olders wrote: 
[snip]
> def main():
> 	a = ['a list','with','three elements']
> 	print a
> 	print fnc1(a)
> 	print a
> 	
> def fnc1(b):
> 	return fnc2(b)
>
> def fnc2(c):
> 	c[1] = 'having'
> 	return c
>
> This is the output:
> ['a list', 'with', 'three elements']
> ['a list', 'having', 'three elements']
> ['a list', 'having', 'three elements']
>
> I had expected the third print statement to give the same
> output as the first, but variable a had been changed by
> changing variable c in fnc2.

For what it's worth, I've noticed that use of the word "variable"
is correlated with a misunderstanding of Python's way of doing
things.  

"Variable" seems to connote a box that has something in it,
so when fnc1 passes b to fnc2 which calls it c, you think
you have a box named b and a box named c, and you wonder
whether the contents of those boxes are the same or
different.

Python works in terms of objects having names, and one
object can have many names.  In your example, fnc1 works
with an object that it calls b, and which it passes to fnc2,
but fnc2 chooses to call that same object c.  The names b
and c aren't boxes that hold things, they are -- in the
words of one of this group's old hands -- sticky-note labels
that have been slapped on the same object.

-- 
To email me, substitute nowhere->spamcop, invalid->net.

[toc] | [prev] | [next] | [standalone]


#6583

FromBen Finney <ben+python@benfinney.id.au>
Date2011-05-30 07:42 +1000
Message-ID<87tycd89qc.fsf@benfinney.id.au>
In reply to#6551
Peter Pearson <ppearson@nowhere.invalid> writes:

> Python works in terms of objects having names, and one
> object can have many names.

Or no names. So it's less accurate (though better than talking of
“variables”) to speak of Python objects “having names”.

> The names b and c aren't boxes that hold things, they are -- in the
> words of one of this group's old hands -- sticky-note labels that have
> been slapped on the same object.

Right. And in that analogy, the object *still* doesn't “have a name”
(since that implies the false conclusion that the object knows its own
name); rather, the name is bound to the object, and the object is
oblivious of this.

I prefer to talk not of sticky notes, but paper tags with string; the
string leading from tag to object is an important part, and the paper
tag might not even have a name written on it, allowing the same analogy
to work for other non-name references like list indices etc.

-- 
 \         “Pinky, are you pondering what I'm pondering?” “I think so, |
  `\   Brain, but where are we going to find a duck and a hose at this |
_o__)                                    hour?” —_Pinky and The Brain_ |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#6631

FromLaurent Claessens <moky.math@gmail.com>
Date2011-05-30 09:12 +0200
Message-ID<irvg1f$qb$1@news.univ-fcomte.fr>
In reply to#6583
Le 29/05/2011 23:42, Ben Finney a écrit :
> Peter Pearson<ppearson@nowhere.invalid>  writes:
>
>>  Python works in terms of objects having names, and one
>>  object can have many names.
>
> Or no names. So it's less accurate (though better than talking of
> “variables”) to speak of Python objects “having names”.

Could you give an example of an object that has no name ? I've missed 
something ...

Laurent

[toc] | [prev] | [next] | [standalone]


#6632

FromChris Rebert <clp2@rebertia.com>
Date2011-05-30 00:27 -0700
Message-ID<mailman.2252.1306740446.9059.python-list@python.org>
In reply to#6631
On Mon, May 30, 2011 at 12:12 AM, Laurent Claessens <moky.math@gmail.com> wrote:
> Le 29/05/2011 23:42, Ben Finney a écrit :
>> Peter Pearson<ppearson@nowhere.invalid>  writes:
>>
>>>  Python works in terms of objects having names, and one
>>>  object can have many names.
>>
>> Or no names. So it's less accurate (though better than talking of
>> “variables”) to speak of Python objects “having names”.
>
> Could you give an example of an object that has no name ? I've missed
> something ...

def foo():
    return 5

print(foo())

The int object 5 has no name here.

Cheers,
Chris

[toc] | [prev] | [next] | [standalone]


#6633

FromLaurent <moky.math@gmail.com>
Date2011-05-30 09:38 +0200
Message-ID<mailman.2253.1306741088.9059.python-list@python.org>
In reply to#6631
>>  Could you give an example of an object that has no name ? I've missed
>>  something ...
>
> def foo():
>      return 5
>
> print(foo())
>
> The int object 5 has no name here.

Cool. I was thinking that "5" was the name, but
 >>> 5.__add__(6)
   File "<stdin>", line 1
     5.__add__(6)
             ^
SyntaxError: invalid syntax

while

 >>> a=5
 >>> a.__add__(6)
11


Very well. I learned something today.
Thanks
Laurent

[toc] | [prev] | [next] | [standalone]


#6634

FromDaniel Kluev <dan.kluev@gmail.com>
Date2011-05-30 19:10 +1100
Message-ID<mailman.2254.1306743025.9059.python-list@python.org>
In reply to#6631
On Mon, May 30, 2011 at 6:12 PM, Laurent Claessens <moky.math@gmail.com> wrote:
> Could you give an example of an object that has no name ? I've missed
> something ...

>>> object()
<object object at 0xb73d04d8>

-- 
With best regards,
Daniel Kluev

[toc] | [prev] | [next] | [standalone]


#6636

FromTerry Reedy <tjreedy@udel.edu>
Date2011-05-30 05:02 -0400
Message-ID<mailman.2255.1306746172.9059.python-list@python.org>
In reply to#6631
On 5/30/2011 3:38 AM, Laurent wrote:

> Cool. I was thinking that "5" was the name, but
>  >>> 5.__add__(6)
> File "<stdin>", line 1
> 5.__add__(6)


Try 5 .__add__(6)

Modules, classes, and functions have a .__name__ attribute (I call it 
their 'definition name') used to print a representation. As best I can 
remember, other builtin objects do not.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#6637

FromLaurent Claessens <moky.math@gmail.com>
Date2011-05-30 11:08 +0200
Message-ID<4DE35E87.8060208@gmail.com>
In reply to#6636
Le 30/05/2011 11:02, Terry Reedy a écrit :
> On 5/30/2011 3:38 AM, Laurent wrote:
>
>>  Cool. I was thinking that "5" was the name, but
>>   >>>  5.__add__(6)
>>  File "<stdin>", line 1
>>  5.__add__(6)
>
>
> Try 5 .__add__(6)

What is the rationale behind the fact to add a space between "5" and 
".__add__" ?
Why does it work ?

Laurent

[toc] | [prev] | [next] | [standalone]


#6639

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-05-30 09:14 +0000
Message-ID<4de35fff$0$29990$c3e8da3$5496439d@news.astraweb.com>
In reply to#6637
On Mon, 30 May 2011 11:08:23 +0200, Laurent Claessens wrote:

> Le 30/05/2011 11:02, Terry Reedy a écrit :
>> On 5/30/2011 3:38 AM, Laurent wrote:
>>
>>>  Cool. I was thinking that "5" was the name, but
>>>   >>>  5.__add__(6)
>>>  File "<stdin>", line 1
>>>  5.__add__(6)
>>
>>
>> Try 5 .__add__(6)
> 
> What is the rationale behind the fact to add a space between "5" and
> ".__add__" ?
> Why does it work ?

Because . is an operator just like + * & etc.

>>> s = "hello world"
>>> s . upper ( )
'HELLO WORLD'


In the case of integer literals, you need the space, otherwise Python 
will parse 5. as a float:


>>> 5.
5.0
>>> 5.__add__
  File "<stdin>", line 1
    5.__add__
            ^
SyntaxError: invalid syntax
>>> 5 .__add__
<method-wrapper '__add__' of int object at 0x8ce3d60>





-- 
Steven

[toc] | [prev] | [next] | [standalone]


#6641

FromBen Finney <ben+python@benfinney.id.au>
Date2011-05-30 19:17 +1000
Message-ID<87ei3g8s43.fsf@benfinney.id.au>
In reply to#6637
Laurent Claessens <moky.math@gmail.com> writes:

> Le 30/05/2011 11:02, Terry Reedy a écrit :
> > Try 5 .__add__(6)
>
> What is the rationale behind the fact to add a space between "5" and
> ".__add__" ?
> Why does it work ?

Try asking it the other way around. Why doesn't ‘5.__add__(6)’, without
the space, work?

-- 
 \        “Telling pious lies to trusting children is a form of abuse, |
  `\                    plain and simple.” —Daniel Dennett, 2010-01-12 |
_o__)                                                                  |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#6646

FromPeter Otten <__peter__@web.de>
Date2011-05-30 11:41 +0200
Message-ID<mailman.2257.1306748481.9059.python-list@python.org>
In reply to#6637
Laurent Claessens wrote:

> Le 30/05/2011 11:02, Terry Reedy a écrit :
>> On 5/30/2011 3:38 AM, Laurent wrote:
>>
>>>  Cool. I was thinking that "5" was the name, but
>>>   >>>  5.__add__(6)
>>>  File "<stdin>", line 1
>>>  5.__add__(6)
>>
>>
>> Try 5 .__add__(6)
> 
> What is the rationale behind the fact to add a space between "5" and
> ".__add__" ?
> Why does it work ?

It's a hint for the tokenizer.

$ cat show_tokens.py
import sys

from tokenize import generate_tokens
from cStringIO import StringIO
from token import tok_name

_name_width = max(len(name) for name in tok_name.itervalues())

def show_tokens(s):
    for token in generate_tokens(StringIO(s).readline):
        name = tok_name[token[0]]
        value = token[1]
        print "%-*s %r" % (_name_width, name, value)

if __name__ == "__main__":
    show_tokens(" ".join(sys.argv[1:]))

$ python show_tokens.py 5.__add__
NUMBER           '5.'
NAME             '__add__'
ENDMARKER        ''

$ python show_tokens.py 5 .__add__
NUMBER           '5'
OP               '.'
NAME             '__add__'
ENDMARKER        ''


[toc] | [prev] | [next] | [standalone]


#6648

FromLaurent Claessens <moky.math@gmail.com>
Date2011-05-30 12:10 +0200
Message-ID<4DE36D03.8050201@gmail.com>
In reply to#6646
>>  What is the rationale behind the fact to add a space between "5" and
>>  ".__add__" ?
>>  Why does it work ?
>
> It's a hint for the tokenizer.

I didn't know the tokenizer. Now I understand.
Thanks

Laurent

[toc] | [prev] | [next] | [standalone]


#6649

FromLaurent Claessens <moky.math@gmail.com>
Date2011-05-30 12:10 +0200
Message-ID<irvqee$1c0$2@news.univ-fcomte.fr>
In reply to#6646
>>  What is the rationale behind the fact to add a space between "5" and
>>  ".__add__" ?
>>  Why does it work ?
>
> It's a hint for the tokenizer.

I didn't know the tokenizer. Now I understand.
Thanks

Laurent

[toc] | [prev] | [next] | [standalone]


#6650

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2011-05-30 13:40 +0300
Message-ID<qotipsszd2k.fsf@ruuvi.it.helsinki.fi>
In reply to#6637
Laurent Claessens writes:
> Le 30/05/2011 11:02, Terry Reedy a écrit :
> > On 5/30/2011 3:38 AM, Laurent wrote:
> >
> >>  Cool. I was thinking that "5" was the name, but
> >>   >>>  5.__add__(6)
> >>  File "<stdin>", line 1
> >>  5.__add__(6)
> >
> >
> > Try 5 .__add__(6)
> 
> What is the rationale behind the fact to add a space between "5" and
> ".__add__" ?
> Why does it work ?

Oh joy.

  >>> [5][0].__add__([6][-1])
  11

The parser just needs the help to detect the intended token boundary
instead of another, unintened one. As the others already say.

[toc] | [prev] | [next] | [standalone]


#6667

FromTerry Reedy <tjreedy@udel.edu>
Date2011-05-30 12:49 -0400
Message-ID<mailman.2275.1306774184.9059.python-list@python.org>
In reply to#6637
On 5/30/2011 5:08 AM, Laurent Claessens wrote:
> Le 30/05/2011 11:02, Terry Reedy a écrit :
>> On 5/30/2011 3:38 AM, Laurent wrote:
>>
>>> Cool. I was thinking that "5" was the name, but
>>> >>> 5.__add__(6)
>>> File "<stdin>", line 1
>>> 5.__add__(6)
>>
>>
>> Try 5 .__add__(6)
>
> What is the rationale behind the fact to add a space between "5" and
> ".__add__" ?
> Why does it work ?

Others have given you specific answers, here is the bigger picture.

For decades, text interpreter/compilers have generally run in two phases:
1. a lexer/tokenizer that breaks the stream of characters into tokens;
2. a parser that recognizes higher-level syntax and takes appropriate 
action.

Lexers are typically based on regular grammars and implemented as very 
simple and fast deterministic finite-state automata. In outline (leaving 
out error handling and end-of-stream handling), something like:

def lexer(stream, lookup, initial_state):
   state = initial_state
   buffer = []
   for char in stream:
     state,out = lookup[state,char]
     if out:
       yield output(buffer)
       # convert list of chars to token expected by parser, clear buffer
     buffer += char

There is no backup and no lookahead (except for the fact that output 
excludes the current char). For python, lookup[start,'5'] == 
in_number,False, and lookup[in_number,'.'] == in_float,False.

 >>> 5..__add__(6)
11.0

works because lookup[in_float,'.'] == start,True, because buffer now 
contains a completed float ready to output and '.' signals the start of 
a new token.

I believe we read natural language text similarly, breaking it into 
words and punctuation. I believe the ability to read programs depends on 
being able to adjust the internal lexer a bit. Python is easier to read 
than some other algorithm languages because it tends to have at most one 
punctuation-like symbol unit between words, as is the case in the code 
above.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#6640

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-05-30 09:16 +0000
Message-ID<4de3606b$0$29990$c3e8da3$5496439d@news.astraweb.com>
In reply to#6631
On Mon, 30 May 2011 09:12:50 +0200, Laurent Claessens wrote:

> Could you give an example of an object that has no name ? I've missed
> something ...


>>> mylist = [None, 42, "something"]


The list object has a name, mylist.

The three objects inside the list have no names.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#6598

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-05-29 23:46 +0000
Message-ID<4de2dab8$0$29996$c3e8da3$5496439d@news.astraweb.com>
In reply to#6521
On Sun, 29 May 2011 04:30:52 -0400, Henry Olders wrote:

> I just spent a considerable amount of time and effort debugging a
> program. The made-up code snippet below illustrates the problem I
> encountered:
[...]
> Are there others who feel as I do that a function parameter should
> always be local to the function? Or am I missing something here?

The nature of Henry's misunderstanding is a disguised version of the very 
common "is Python call by reference or call by value?" question that 
periodically crops up. I wrote a long, but I hope useful, explanation for 
the tutor@python.org mailing list, which I'd like to share here:

http://mail.python.org/pipermail/tutor/2010-December/080505.html


Constructive criticism welcome.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.python


csiph-web