Mailing List Archive

1 2 3  View All
Re: LOAD_NAME & classes [ In reply to ]
Greg Ewing wrote:
>
> Guido:
>
> > def f():
> > print x # user thinks this should print the global
> > # 2000 lines of unrelated code
> > for x in "some sequence": # doesn't realize this overrides x
> > do_something_with(x)
>
> Perhaps a warning could be issued if the first reference
> to a local textually precedes the first assignment to it?
> Would that help catch things like this, without complaining
> about too much existing code?

The standard library has 4 such occurrences:

ftplib.py:678: Variable (macro_lines) used before being set
ftplib.py:681: Variable (macro_name) used before being set
tokenize.py:148: Variable (strstart) used before being set
tokenize.py:149: Variable (endprog) used before being set

The line numbers are from CVS version subtract 77/20 for 2.2.1.

Neal
Re: Re: LOAD_NAME & classes [ In reply to ]
On Tue, Apr 23 @ 17:45, Guido van Rossum wrote:
> I'm not sure that every possible handy coding tip deserves to be in
> the documentation. There ought to be (and are!) plenty of other
> introductory texts that can serve this purpose.
>
> Also, in this particular case, the question ("how do I share data
> between modules") and the answer ("put it in a module and import it")
> seems pretty obvious once you have a decent grip of module semantics.

I agree now as well. I wouldn't have when I started though. At the
time I wondered if I had committed a stylistic sin because it didn't
feel "right".

-- Mike

--
Michael Gilfix
mgilfix@eecs.tufts.edu

For my gpg public key:
http://www.eecs.tufts.edu/~mgilfix/contact.html
Re: LOAD_NAME & classes [ In reply to ]
Michael Gilfix <mgilfix@eecs.tufts.edu>:

> The our is akin to declaring something static in C.

Except that it sounds like if two functions declare
"our" variables with the same name, they get the
same variable, whereas in C they would be different
variables. (I think -- it just occurred to me that
I'm not really sure about that!)

Greg Ewing, Computer Science Dept, +--------------------------------------+
University of Canterbury, | A citizen of NewZealandCorp, a |
Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. |
greg@cosc.canterbury.ac.nz +--------------------------------------+
RE: LOAD_NAME & classes [ In reply to ]
[Guido]
> ...
> This particular form of breakage was a common error reported on c.l.py
> and to help at python.org until we added UnboundLocalError to make the
> diagnostic cleaner.

It was indeed, and adding UnboundLocalError did cut the number of questions.

> Maybe that's all that's needed;

It's hard to know what could really help more. If Greg Wilson is still
running newcomer experiments, I'd like to see what newcomers have to say
about this:


x = 2
def f():
print x # A
x = 3

f()
print x # B


A: What do you think should happen when the print at A executes?
B: " " " " " " " " " " B " ?

What I suspect, but don't know, is that a majority of newcomers who expect A
to print 2 *also* expect B to print 3. That is, that they're thinking x is
a global variable, and have no conception of local variables in mind.

This is actually what happens in Icon, which also lacks declarations (in the
same sense Python lacks them: it doesn't lack them <wink>). The difference
is that all variables are global by default in Icon, and you need to
explicitly say "local x" if you want a local var instead. That's
error-prone for sure, by not quite as much so as Perl (where x is also
global by default, but "local $x" sucks you into dynamic scoping; it does
not in Icon).
Re: LOAD_NAME & classes [ In reply to ]
> > def f():
> > print x # user thinks this should print the global
> > # 2000 lines of unrelated code
> > for x in "some sequence": # doesn't realize this overrides x
> > do_something_with(x)
>
> Perhaps a warning could be issued if the first reference
> to a local textually precedes the first assignment to it?
> Would that help catch things like this, without complaining
> about too much existing code?

Absolutely, and I believe that's what PyChecker is doing. Getting it
added to Python's own compiler is tricky though -- maybe we should put
off all such enhancements until Jeremy's new AST-based compiler is
finished.

--Guido van Rossum (home page: http://www.python.org/~guido/)
Re: LOAD_NAME & classes [ In reply to ]
[Tim]
> It's hard to know what could really help more. If Greg Wilson is
> still running newcomer experiments, I'd like to see what newcomers
> have to say about this:
>
>
> x = 2
> def f():
> print x # A
> x = 3
>
> f()
> print x # B
>
>
> A: What do you think should happen when the print at A executes?
> B: " " " " " " " " " " B " ?
>
> What I suspect, but don't know, is that a majority of newcomers who
> expect A to print 2 *also* expect B to print 3. That is, that
> they're thinking x is a global variable, and have no conception of
> local variables in mind.

That's not a fair experiment until after you've given them a good
concept of local and global variables without name conflicts. On the
one hand, the importance of having local variables at all isn't clear
if there are no name conflicts (until you introduce recursion, which I
would *definitely* introduce much later, despite Matthias Felleisen's
teachings :-). But on the other hand, it's easy to show that after

>>> def f():
... greeting = "hello world"
... print greeting
...
>>> f()
hello world
>>> print greeting
NameError: greeting
>>>

there's no global variable 'greeting', which can then be used to
explain that variable assignments create local variables. You don't
need to explain the *reason* for this feature at this point; that'll
be clear by the time you've explained the rest. Next you can explain
the global statement. This appears irrelevant to the proposed
experiment, but it's useful to take away fears that you can't change
globals at all: people coming from other languages will know that that
is important, and worry how Python deals with this. After that you
can show how name conflicts are handled in the "normal" case, where
you shadow a global in a function by assigning to it and then using
it, without a global statement. At some point you should also point
out that if you don't *change* a global, you can use in a function it
without the global statement. This comes so natural that it's easy to
gloss over, especially when the "global" in question is a function or
an imported module; but it *is* an important feature.

*THEN* you are ready for the experiment Tim proposes above.

--Guido van Rossum (home page: http://www.python.org/~guido/)
RE: LOAD_NAME & classes [ In reply to ]
--- Tim Peters <tim.one@comcast.net> wrote:
>
> This is actually what happens in Icon, which also lacks declarations (in
> the same sense Python lacks them: it doesn't lack them <wink>). The
> difference
> is that all variables are global by default in Icon, and you need to
> explicitly say "local x" if you want a local var instead. That's
> error-prone for sure, by not quite as much so as Perl (where x is also
> global by default, but "local $x" sucks you into dynamic scoping; it does
> not in Icon).
>

A few corrections. New variable names were local by default. The only way
to get a global variable was to make a "global varname" statement at the
global scope. Icon gave you a None-like value, &null, for your variables
if you hadn't already assigned to them somewhere. So strictly speaking,
you could read a variable before writing to it, and a declaration (first
initialization) wasn't necessary the same way it is in Python.

Using "local x" was strongly recommended because (a) you could use the -u
switch of icont to warn you when you didn't declare your locals (usually
from typos), and (b) in case you forgot that you used the same name as a
global somewhere else, or more likely you "link"ed with a file that had
global declarations you weren't aware of.

So it really wasn't so error prone. (Icon's not even close to Perl in this
regard. :-)

Cheers,
-Scott





__________________________________________________
Do You Yahoo!?
Yahoo! Games - play chess, backgammon, pool and more
http://games.yahoo.com/
Re: LOAD_NAME & classes [ In reply to ]
On Wednesday 24 April 2002 04:40, Greg Ewing wrote:
> Michael Gilfix <mgilfix@eecs.tufts.edu>:
> > The our is akin to declaring something static in C.
>
> Except that it sounds like if two functions declare
> "our" variables with the same name, they get the
> same variable, whereas in C they would be different
> variables. (I think -- it just occurred to me that
> I'm not really sure about that!)

You think correctly: two C functions declaring static
function-scope variables with the same name get
different variables. static variables at FILE scope are
'shared' throughout the file, but not between files.


Alex
Re: LOAD_NAME & classes [ In reply to ]
Tim Peters <tim.one@comcast.net> writes:

> [Michael Hudson, on UnboundLocalErrors]
> > ...
> > Wouldn't it be nice if these were flagged at compile time! More work
> > for Jeremy <wink>.
>
> As will (or already has <wink>) been pointed out, the compiler can only
> guess, and can't always guess right (it could err on the side of bothering
> you without cause, though).

That's what I was implying, yes.

> PyChecker goes a long way already. Java has a mass of "definite
> assignment" rules instead, which in effect decree that you must
> write code in such a way that the compiler can always guess right.

Are these explained in an easy to digest form somewhere?

Cheers,
M.

--
I saw `cout' being shifted "Hello world" times to the left and
stopped right there. -- Steve Gonedes
Re: LOAD_NAME & classes [ In reply to ]
On Wednesday 24 April 2002 13:13, Michael Hudson wrote:
...
> > PyChecker goes a long way already. Java has a mass of "definite
> > assignment" rules instead, which in effect decree that you must
> > write code in such a way that the compiler can always guess right.
>
> Are these explained in an easy to digest form somewhere?

http://java.sun.com/docs/books/jls/second_edition/html/defAssign.doc.html

Alex
Re: LOAD_NAME & classes [ In reply to ]
> > PyChecker goes a long way already. Java has a mass of "definite
> > assignment" rules instead, which in effect decree that you must
> > write code in such a way that the compiler can always guess right.
>
> Are these explained in an easy to digest form somewhere?

Dunno, but I can easily guess the gist of it: a variable is only
defined on paths if it would still always be defined if all
conditional statements randomly chose between true or false, and all
loops executed a random number of times which may include zero. I
assume that this means dependencies between variables are out (these
made the examples reported by Neil work).

--Guido van Rossum (home page: http://www.python.org/~guido/)
RE: LOAD_NAME & classes [ In reply to ]
[Guido, on
> x = 2
> def f():
> print x # A
> x = 3
>
> f()
> print x # B
>
>
> A: What do you think should happen when the print at A executes?
> B: " " " " " " " " " " B " ?
]

> That's not a fair experiment until after you've given them a good
> concept of local and global variables without name conflicts.

I think my point is getting lost twice:

1. My suspicion is that the majority of people I've explained this
to, over the years and years, would have answered the equivalent
to "well, B should print 3, of course!", when translated to the
specific context in which their confusion arose. That is, I suspect
they didn't understand local variables at all, not they that had
some vision of "well, it's the global name unless and until I
dynamically override it with a local name, at which point the
global name with the same spelling is no longer relevant".

2. If we're talking about people willing to be taught "a good concept
of local and global variables" before going postal, there's
no "problem" to be solved here! I suspect even Mr. Kuchling
understands how local variables work today <wink>.

> ...
> But on the other hand, it's easy to show that after ...
> which can then be used to explain that variable assignments create
> local variables.
> You don't need to explain the *reason* for this feature at this point ..
> Next you can explain the global statement ...
> After that you can show how name conflicts are handled ...
> At some point you should also point out that ...
> *THEN* you are ready for the experiment Tim proposes above.

Anyone willing to sit through that much explanation will have no problem
understanding how locals work today. Besides, if you get to tell them
beforehand that "variable assigments *create* local variables" dynamically,
then I get to tell them beforehand that variable assignments don't create
local variables dynamically. At that point we'd only be testing how
faithfully they can regurgitate what they've just been told.

I'm not a sure a difference between 12% comprehension rate and 13%
comprehension rate is statistically significant anyway <0.9 wink>.
RE: LOAD_NAME & classes [ In reply to ]
[Scott Gilbert, on Icon]
> A few corrections. New variable names were local by default.

Ack! You're right! Years of stuffing in "local" decls made me forget why
they were recommended to begin with.

> The only way to get a global variable was to make a "global varname"
> statement at the global scope.

The difficulty being-- why explicit "local" was really recommended --that a
new global magically changes every *implicit* local vrbl of the same name
into a global. This bit too when an implicit local happened to have the
same name as a new function added later, because function names are
automatically global. Like:

procedure main()
f()
g()
end

procedure f()
count := 1
while count < 10 do count +:= 1
write(count)
end

procedure g()
write(len([2, 3, 4]) | "oops!")
end

procedure len(x)
return *x
end

That prints

10
3

If you just happen to change the name of the "len" function to "count"
later:

procedure g()
write(count([2, 3, 4]) | "oops!")
end

procedure count(x)
return *x
end


it suddenly prints

10
oops!

instead (the expression

count([2, 3, 4]) | "oops!"

becomes

10([2, 3, 4]) | "oops!"

because the once-local "count" in f is suddenly global, and retains its
value of 10; then 10([2, 3, 4]) fails, and the alternative "oops!" is tried
and succeeds).

In real life these could be an absolute bitch to track down, so I always
used local. Insert

local count

at the top of f and everything's fine again.

> Icon gave you a None-like value, &null, for your variables if you
> hadn't already assigned to them somewhere. So strictly speaking,
> you could read a variable before writing to it, and a declaration (first
> initialization) wasn't necessary the same way it is in Python.

I prefer Python distinguishing between None and unbound too; e.g., I'd much
rather have

x := y

blow up at once if y hasn't been bound than to silently propagate &null (or
a Python None). &null could travel *all over the place* before you finally
hit an expression where it didn't just silently fail (very few things in
Icon raise errors, as the 10([2, 3, 4]) example should have suggested to
onlookers <wink>).

> Using "local x" was strongly recommended because (a) you could use the
> -u switch of icont to warn you when you didn't declare your locals
> (usually from typos),

Unfortunately, -u doesn't complain about the "10 oops!" example above: as
far as it's concerned, all variables were declared in that example.
Fortunately, it does complain about the original way of writing it, because
"count" is undeclared then.

> and (b) in case you forgot that you used the same name as a global
> somewhere else, or more likely you "link"ed with a file that had global
> declarations you weren't aware of.

Like an implicit "import *" in Python -- we're well aware of the dangers of
*that* around here <wink>.

> So it really wasn't so error prone. (Icon's not even close to
> Perl in this regard. :-)

Not for scope rules alone, no, although Perl sticking to explicit "my"
everywhere isn't much worse than Icon sticking to explicit "local"
everywere.
RE: LOAD_NAME & classes [ In reply to ]
--- Tim Peters <tim.one@comcast.net> wrote:
>
> instead (the expression
>
> count([2, 3, 4]) | "oops!"
>
> becomes
>
> 10([2, 3, 4]) | "oops!"
>
> because the once-local "count" in f is suddenly global, and retains its
> value of 10; then 10([2, 3, 4]) fails, and the alternative "oops!" is
> tried
> and succeeds).
>

Yep that's ugly. I never wrote any programs in Icon larger than a couple
thousand lines, and I never used Icon in a team setting, so I didn't get
bit by things like this.


>
> I prefer Python distinguishing between None and unbound too; e.g., I'd
> much
> rather have
>
> x := y
>
> blow up at once if y hasn't been bound than to silently propagate &null
>

I have mixed feelings on this one. I remember using the / and \ operators
all over the place to work around it, so in that regard I guess I didn't
like it. On the other hand it nicely parallels how tables would return
&null (or other default) for keys that weren't already in there, and that I
liked.

In Python, I use the d.get('key', default) construct quite a bit. Probably
because I learned to like getting a default value from Icon. I could use a
DefaultDict class derived from dict, but that's less convenient and doesn't
help me with **kwds arguments. Plus it's a hindrance to someone reading my
code who knows what Pythonic behavior is supposed to be.

No one says that key lookup in dicts/tables and variable lookup in the
namespace have to follow the same rules though. It just seems that they do
in both Icon and Python. Each with a different choice for rules.

>
> (very few things in
> Icon raise errors, as the 10([2, 3, 4]) example should have suggested to
> onlookers <wink>).
>

I took two Icon courses from Ralph, and several times while sitting in
class, I got the impression that he regretted a lot of things like this.
Having integers usable in the place of functions was odd and rarely useful.
He also didn't seem to have much respect for co-expressions. He was
really excited about the graphics features though.

Now *strings* as functions, that I used. :-)

I think part of the charm of Icon was* that it felt like an experiment to
see what cool new concepts come out of letting anything do everything.
When it comes time to teach it or use it in a large project, having the
language force a little more bondage is probably a good thing.


* - I should say "charm of Icon is". It looks like it's still got
something of a pulse in academia... In fact the latest version just built
under Cygwin without major headaches.

>
> Unfortunately, -u doesn't complain about the "10 oops!" example above:
> as
>

Yeah, a -U-and-I-really-mean-it flag would fix this. :-)

Maybe if procedures were "const" the problem would go away. (While
probably creating some new problem that I'm not thinking of...)


Trying to draw this back as relevant to Python and this thread:

I think Icon has an easier time with scoping rules than Python because
execution starts in "procedure main()", not the beginning of the file.
Since code isn't floating out there at the topmost level, one can't create
variables there without an explicit global declaration. There really are
only two scopes for global and local. (And some builtins of course...)

Following this thread and reading some of the examples, I don't think I
have a deep grasp of what the rules are in Python. I just have a set of
conventions that I follow which seem to keep me out of trouble.

Your example of:

x = 2
def f():
print x
#x = 3 ### uncomment to go BOOM

kind of surprised me. I presented it to another co-worker who wasn't very
Python savvy. It caught me off guard that he expected the exception at the
print statement, but he didn't realize it only occurs when you have the
"local declaration" later.

>
> Like an implicit "import *" in Python -- we're well aware of the dangers
> of *that* around here <wink>.
>

Yep, and I litter my libraries with underscores to protect from it. A
number of users at my company gripe about having to use parens and commas
for function calls, especially in interactive mode, so convincing them to
use module.function(arg, arg, arg) is going to be a really tough sell...
(Someone suggested the LazyPython hack as a sort of solution to the first
problem, but they would prefer "import module" defaulted to the bad
behavior)

The underscores also make it easy to see when something is global or not,
avoiding the BOOM in your example above.


> > So it really wasn't so error prone. (Icon's not even close to
> > Perl in this regard. :-)
>
> Not for scope rules alone, no, although Perl sticking to explicit "my"
> everywhere isn't much worse than Icon sticking to explicit "local"
> everywhere.
>

My nostalgia for Icon makes me forget about any of the bad things. I don't
have much nostalgia for Perl, so it's faults I remember.


Cheers,
-Scott



__________________________________________________
Do You Yahoo!?
Yahoo! Games - play chess, backgammon, pool and more
http://games.yahoo.com/

1 2 3  View All