Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #6522 > unrolled thread
| Started by | Wolfgang Rohdewald <wolfgang@rohdewald.de> |
|---|---|
| First post | 2011-05-29 11:47 +0200 |
| Last post | 2011-05-29 13:12 -0600 |
| Articles | 9 — 5 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: scope of function parameters Wolfgang Rohdewald <wolfgang@rohdewald.de> - 2011-05-29 11:47 +0200
Re: scope of function parameters Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-05-29 12:47 +0000
Re: scope of function parameters Chris Angelico <rosuav@gmail.com> - 2011-05-30 03:53 +1000
Re: scope of function parameters Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-05-29 18:28 +0000
Re: scope of function parameters Chris Rebert <clp2@rebertia.com> - 2011-05-29 11:01 -0700
Re: scope of function parameters Chris Angelico <rosuav@gmail.com> - 2011-05-30 04:38 +1000
Re: scope of function parameters Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-05-29 18:53 +0000
Re: scope of function parameters Chris Angelico <rosuav@gmail.com> - 2011-05-30 05:20 +1000
Re: scope of function parameters Ian Kelly <ian.g.kelly@gmail.com> - 2011-05-29 13:12 -0600
| From | Wolfgang Rohdewald <wolfgang@rohdewald.de> |
|---|---|
| Date | 2011-05-29 11:47 +0200 |
| Subject | Re: scope of function parameters |
| Message-ID | <mailman.2217.1306662671.9059.python-list@python.org> |
On Sonntag 29 Mai 2011, Henry Olders wrote:
> It seems that in Python, a variable inside a function is
> global unless it's assigned.
no, they are local
> 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 is local. But consider what you actually passed:
You did not pass a copy of the list but the list itself.
You could also say you passed a reference to the list.
All python variables only hold a pointer (the id) to
an object. This object has a reference count and is
automatically deleted when there are no more references
to it.
If you want a local copy of the list you can either
do what you called being ugly or do just that within
the function itself - which I think is cleaner and
only required once.
def fnc2(c):
c = c[:]
c[1] = 'having'
return c
--
Wolfgang
[toc] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-05-29 12:47 +0000 |
| Message-ID | <4de24045$0$29996$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #6522 |
On Sun, 29 May 2011 11:47:26 +0200, Wolfgang Rohdewald wrote:
> On Sonntag 29 Mai 2011, Henry Olders wrote:
>> It seems that in Python, a variable inside a function is global unless
>> it's assigned.
>
> no, they are local
I'm afraid you are incorrect. Names inside a function are global unless
assigned to somewhere.
>>> a = 1
>>> def f():
... print a # Not local, global.
...
>>> f()
1
By default, names inside a function must be treated as global, otherwise
you couldn't easily refer to global functions:
def f(x):
print len(x)
because len would be a local name, which doesn't exist. In Python, built-
in names are "variables" just like any other.
Python's scoping rule is something like this:
If a name is assigned to anywhere in the function, treat it as a local,
and look it up in the local namespace. If not found, raise
UnboundLocalError.
If a name is never assigned to, or if it is declared global, then look it
up in the global namespace. If not found, look for it in the built-ins.
If still not found, raise NameError.
Nested scopes (functions inside functions) make the scoping rules a
little more complex.
If a name is a function parameter, that is equivalent to being assigned
to inside the function.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2011-05-30 03:53 +1000 |
| Message-ID | <mailman.2229.1306691607.9059.python-list@python.org> |
| In reply to | #6531 |
On Sun, May 29, 2011 at 10:47 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > If a name is assigned to anywhere in the function, treat it as a local, > and look it up in the local namespace. If not found, raise > UnboundLocalError. > Wait wha? I've never seen this... wouldn't it just create it in the local namespace? Can you give example code that will trigger this error? I'm curious, now... Chris Angelico
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-05-29 18:28 +0000 |
| Message-ID | <4de29043$0$29996$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #6555 |
On Mon, 30 May 2011 03:53:24 +1000, Chris Angelico wrote:
> On Sun, May 29, 2011 at 10:47 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> If a name is assigned to anywhere in the function, treat it as a local,
>> and look it up in the local namespace. If not found, raise
>> UnboundLocalError.
>>
>>
> Wait wha? I've never seen this... wouldn't it just create it in the
> local namespace?
>
> Can you give example code that will trigger this error? I'm curious,
> now...
def f():
print a # a is not yet defined, i.e. unbound
a = 1 # this makes a local
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Chris Rebert <clp2@rebertia.com> |
|---|---|
| Date | 2011-05-29 11:01 -0700 |
| Message-ID | <mailman.2231.1306692087.9059.python-list@python.org> |
| In reply to | #6531 |
On Sun, May 29, 2011 at 10:53 AM, Chris Angelico <rosuav@gmail.com> wrote:
> On Sun, May 29, 2011 at 10:47 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> If a name is assigned to anywhere in the function, treat it as a local,
>> and look it up in the local namespace. If not found, raise
>> UnboundLocalError.
>>
>
> Wait wha? I've never seen this... wouldn't it just create it in the
> local namespace?
>
> Can you give example code that will trigger this error? I'm curious, now...
def foo():
print bar
bar = 42
foo()
===>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'bar' referenced before assignment
Cheers,
Chris
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2011-05-30 04:38 +1000 |
| Message-ID | <mailman.2233.1306694309.9059.python-list@python.org> |
| In reply to | #6531 |
On Mon, May 30, 2011 at 4:01 AM, Chris Rebert <clp2@rebertia.com> wrote: > def foo(): > print bar > bar = 42 > > foo() > > ===> > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > File "<stdin>", line 2, in foo > UnboundLocalError: local variable 'bar' referenced before assignment Wow I thought it basically functioned top-down. You get a different error on the print line if there's a "bar = 42" *after* it. This could make debugging quite confusing. Guess it's just one of the consequences of eschewing variable declarations. Sure it's easier, but there's complications down the road. Chris Angelico
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-05-29 18:53 +0000 |
| Message-ID | <4de29612$0$29996$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #6561 |
On Mon, 30 May 2011 04:38:26 +1000, Chris Angelico wrote: > On Mon, May 30, 2011 at 4:01 AM, Chris Rebert <clp2@rebertia.com> wrote: >> def foo(): >> print bar >> bar = 42 >> >> foo() >> >> ===> >> Traceback (most recent call last): >> File "<stdin>", line 1, in <module> >> File "<stdin>", line 2, in foo >> UnboundLocalError: local variable 'bar' referenced before assignment > > Wow > > I thought it basically functioned top-down. You get a different error on > the print line if there's a "bar = 42" *after* it. This could make > debugging quite confusing. UnboundLocalError is a subclass of NameError, so it will still be caught by try...except NameError. If you're crazy enough to be catching NameError :) Go back to Python1.5, and there was no UnboundLocalError. It was introduced because people were confused when they got a NameError after forgetting to declare something global: >>> def f(): ... print a ... a = a + 1 ... >>> a = 42 >>> f() Traceback (innermost last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in f NameError: a While UnboundLocalError is jargon, and not the easiest error message to comprehend, at least it confuses in a different way :) -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2011-05-30 05:20 +1000 |
| Message-ID | <mailman.2235.1306696854.9059.python-list@python.org> |
| In reply to | #6563 |
On Mon, May 30, 2011 at 4:53 AM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> UnboundLocalError is a subclass of NameError, so it will still be caught
> by try...except NameError.
>
> If you're crazy enough to be catching NameError :)
Ah okay. So it is still NameError, it just doesn't look like one.
> While UnboundLocalError is jargon, and not the easiest error message to
> comprehend, at least it confuses in a different way :)
I have nothing against jargon, and specific errors are better than
generic ones (imagine if every error were thrown as Exception with a
string parameter... oh wait, that's what string exceptions are).
It still seems a little odd that a subsequent line can affect this
one. But Python's mostly doing what would be expected of it; the worst
I can come up with is this:
def f():
print(foo) # reference a global
...
for foo in bar: # variable only used in loop
pass
If you're used to C++ and declaring variables inside a for loop eg
"for (int i=0;i<10;++i)", you might not concern yourself with the fact
that 'foo' is masking a global; it's not an issue, because you don't
need that global inside that loop, right? And it would be fine, except
that that global IS used somewhere else in the function. It'd be a bit
confusing to get the UnboundLocalError up on the print(foo) line (the
one that's meant to be using the global), since that line isn't wrong;
and the "obvious fix", adding an explicit "global foo" to the top of
the function, would be worse (because it would mean that the for loop
overwrites the global).
This is why I would prefer to declare variables. The Zen of Python
says that explicit is better than implicit, but in this instance,
Python goes for DWIM, guessing whether you meant global or local. It
guesses fairly well, though.
Chris Angelico
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2011-05-29 13:12 -0600 |
| Message-ID | <mailman.2234.1306696367.9059.python-list@python.org> |
| In reply to | #6531 |
On Sun, May 29, 2011 at 12:38 PM, Chris Angelico <rosuav@gmail.com> wrote: > I thought it basically functioned top-down. You get a different error > on the print line if there's a "bar = 42" *after* it. This could make > debugging quite confusing. > > Guess it's just one of the consequences of eschewing variable > declarations. Sure it's easier, but there's complications down the > road. It's also a consequence of local variable access being optimized with different bytecode: the type of storage has to be determined at compile time. The compiler could in principle figure out that "bar" cannot be bound at that point and make it a global reference, but it is easy to concoct situations involving loops or conditionals where the storage cannot be determined at compile time, and so the compiler follows the simple rule of making everything local unless it's never assigned. Cheers, Ian
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web