From: Ethan Furman on
Alf P. Steinbach /Usenet wrote:
> * MRAB, on 12.07.2010 00:37:
>> Alf P. Steinbach /Usenet wrote:
>>>
>>> Of course there are variables, that's why the docs call them variables.
>>>
>> In Java a variable is declared and exists even before the first
>> assignment to it. In Python a 'variable' isn't declared and won't exist
>> until the first 'assignment' to it.
>
> That is a misconception.
>
> In Python a variable is declared by having an assignment to it, which
> for a local variable may be anywhere within a routine.
>
> If such a variable is used before it's been assigned to, then you get an
> uninitialized variable exception. Clearly the variable must exist in
> order for the exception to refer to it (not to mention the exception
> occurring at all).

Really? So it's impossible for the interpreter, upon seeing the name
'blah', to scan forward to see if 'blah' is somewhere in the function in
order to give a more meaningful error message? Of course not.


> def foo():
> print( blah )
> blah = "this is both an assignment and a declaration causing it to
> exist"
>
> foo()
>
> Clearly when the exception is raised, referring to the variable, the
> variable exists.

You are the only one spouting nonsense. Have you tried this?

--> def foo():
.... print locals()
.... blah = 'interesting'
.... print locals()
....
--> foo()
{}
{'blah': 'interesting'}

As can be clearly seen, blah does not exist before the assignment -- the
*name* blah has not been *bound* to an object yet, which is also what
the error message says when you try to use it before it exists:

UnboundLocalError: local variable 'blah' referenced before assignment

Nothing religious about it -- just the facts.

~Ethan~
From: Steven D'Aprano on
On Wed, 14 Jul 2010 09:06:34 -0700, Ethan Furman wrote:

> Alf P. Steinbach /Usenet wrote:
[...]
>> Clearly when the exception is raised, referring to the variable, the
>> variable exists.
>
> You are the only one spouting nonsense. Have you tried this?
>
> --> def foo():
> ... print locals()
> ... blah = 'interesting'
> ... print locals()
> ...
> --> foo()
> {}
> {'blah': 'interesting'}
>
> As can be clearly seen, blah does not exist before the assignment -- the
> *name* blah has not been *bound* to an object yet, which is also what
> the error message says when you try to use it before it exists:

While I agree with your basic position that, in a meaningful sense,
"blah" does not exist before it is assigned to, your explanation is
invalid.

In CPython, local variables in functions are optimised into pre-allocated
slots. locals() is a *copy* of the actual locals, and any locals which
are allocated but not defined are suppressed from the dict.

>>> def f():
.... x = 5
.... if y:
.... z = 1
.... return x+z
....
>>> f.func_code.co_nlocals
2
>>> f.func_code.co_freevars
()
>>> f.func_code.co_varnames
('x', 'z')

More here:
http://tech.blog.aknin.name/2010/07/03/pythons-innards-code-objects/

You'll notice that in the sense of having space allocated for them in the
code object, the variables already exist before the function has even
been executed. But of course that's not the only sense, or even the most
important one. I would argue that, in a very real sense, if you call f()
with the global y set to False, that *semantically* the local z doesn't
exist, even if the error message says different:

> UnboundLocalError: local variable 'z' referenced before assignment


--
Steven

From: John Posner on
On 7/14/2010 12:06 PM, Ethan Furman wrote:

> ... Have you tried this?
>
> --> def foo():
> ... print locals()
> ... blah = 'interesting'
> ... print locals()
> ...
> --> foo()
> {}
> {'blah': 'interesting'}
>
> As can be clearly seen, blah does not exist before the assignment -- the
> *name* blah has not been *bound* to an object yet, which is also what
> the error message says when you try to use it before it exists:

As already cited, according to Section 4.1 "Naming and binding" in the
Language Reference, the name "blah" *does* exist before the assignment.
That's the implication of this phrase:

If the name refers to a local variable that has not been bound,

(BTW, "has not been bound" should really be "is not currently bound", to
allow for use of *del* earlier in the block.)

Try this:

#--------------
def foo():
print "1. varnames:", globals()['foo'].__code__.co_varnames
print "2. locals:", locals()
blah = 'interesting'
print "3. locals:", locals()

foo()
#--------------

The output (Python 2.6.5) is:

1. varnames: ('blah',)
2. locals: {}
3. locals: {'blah': 'interesting'}

-John
From: Grant Edwards on
On 2010-07-11, wheres pythonmonks <wherespythonmonks(a)gmail.com> wrote:

> I have some easy issues (Python 2.6)

As of a few minutes ago, this thread had 48 postings on my news
server.

To paraphrase somebody famous:

There are no such things as easy questions. There are, however,
easy answers. And they're wrong.

--
Grant Edwards grant.b.edwards Yow! Did I say I was
at a sardine? Or a bus???
gmail.com
From: r on
On Jul 14, 1:24 pm, Grant Edwards <inva...(a)invalid.invalid> wrote:

> As of a few minutes ago, this thread had 48 postings on my news
> server.
>
> To paraphrase somebody famous:
>
>     There are no such things as easy questions.  There are, however,
>     easy answers.  And they're wrong.        

Ha! This is the very reason i always steer clear of any post with the
words "easy", "simple", or "BUSTARDS" in the title. ;-)