Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #6521 > unrolled thread
| Started by | Henry Olders <henry.olders@mcgill.ca> |
|---|---|
| First post | 2011-05-29 04:30 -0400 |
| Last post | 2011-05-31 10:33 -0700 |
| Articles | 20 on this page of 27 — 14 participants |
Back to article view | Back to comp.lang.python
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 →
| From | Henry Olders <henry.olders@mcgill.ca> |
|---|---|
| Date | 2011-05-29 04:30 -0400 |
| Subject | scope 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]
| From | Mel <mwilson@the-wire.com> |
|---|---|
| Date | 2011-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]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-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]
| From | Peter Pearson <ppearson@nowhere.invalid> |
|---|---|
| Date | 2011-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]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2011-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]
| From | Laurent Claessens <moky.math@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Chris Rebert <clp2@rebertia.com> |
|---|---|
| Date | 2011-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]
| From | Laurent <moky.math@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Daniel Kluev <dan.kluev@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-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]
| From | Laurent Claessens <moky.math@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-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]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2011-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]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2011-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]
| From | Laurent Claessens <moky.math@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Laurent Claessens <moky.math@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Jussi Piitulainen <jpiitula@ling.helsinki.fi> |
|---|---|
| Date | 2011-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]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-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