By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,677 Members | 1,128 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,677 IT Pros & Developers. It's quick & easy.

loop scope

P: n/a
a=[1,2,3]
for p in a: print p
1
2
3 p 3

My naive expectation was that p would be 'not defined' from outside
the loop.

I know this is not news.

In fact I had come across some discussion of this fact, but apparently
didn't register it.

As I got myself surprised by it - specifically in the context of list
comps, where I think it is particularly surprising:
b=[4,5,6]
[t*2 for t in b] [8, 10, 12] t

6

Is this anywhere useful, or more of an artifact?

Art

Jul 18 '05 #1
Share this Question
Share on Google+
33 Replies


P: n/a

"Arthur" <aj******@optonline.com> wrote in message
news:f8********************************@4ax.com...
a=[1,2,3]
for p in a: print p
1
2
3 p 3

My naive expectation was that p would be 'not defined' from outside
the loop.

I know this is not news.

In fact I had come across some discussion of this fact, but apparently
didn't register it.

As I got myself surprised by it - specifically in the context of list
comps, where I think it is particularly surprising:
b=[4,5,6]
[t*2 for t in b] [8, 10, 12] t

6

Is this anywhere useful, or more of an artifact?


For loops with a break statement, the value of the loop index when the
break occurs may be the answer sought or needed to calculate it. For list
comps which cannot have break, it is an artifact which may disappear in
2.4.

Terry J. Reedy


Jul 18 '05 #2

P: n/a
On Thu, 11 Mar 2004 21:08:09 GMT, Arthur <aj******@optonline.com>
wrote:
a=[1,2,3]
for p in a: print p
1
2
3 p3

My naive expectation was that p would be 'not defined' from outside
the loop.

I know this is not news.

In fact I had come across some discussion of this fact, but apparently
didn't register it.

As I got myself surprised by it - specifically in the context of list
comps, where I think it is particularly surprising:
b=[4,5,6]
[t*2 for t in b][8, 10, 12] t

6

Is this anywhere useful, or more of an artifact?


Scopes are defined by the boundaries of functions, classes and
modules, not for loops. This is essential, or you would have to
declare global variables inside most for loops.

For a good, up-to-date discussion of scopes, see Learning Python, Ch.
13 Scopes and Arguments, and p.337 - Namespaces: The Whole Story. Be
sure to get the 2nd edition. The scope rules have changed
significantly since the first edition.

-- Dave

Jul 18 '05 #3

P: n/a
Terry Reedy wrote:
For loops with a break statement, the value of the loop index when the
break occurs may be the answer sought or needed to calculate it. For list
comps which cannot have break, it is an artifact which may disappear in
2.4.


If I understand you, I don't think I like this idea. It
adds complexity to the mental model of a loop. "The
loop variable disappears when the loop ends unless the
loop contains a break".

In my opinion, Python should pick a model and stick to
it. Loop variables are either ordinary variables that
exist until you explicitly delete them, or they are
special variables that automagically disappear at the
end of the loop. I vote for the first one.
--
Steven D'Aprano
Jul 18 '05 #4

P: n/a
Quoth us**@domain.invalid:
| Terry Reedy wrote:
|
|> For loops with a break statement, the value of the loop index when the
|> break occurs may be the answer sought or needed to calculate it. For list
|> comps which cannot have break, it is an artifact which may disappear in
|> 2.4.
|
| If I understand you, I don't think I like this idea. It
| adds complexity to the mental model of a loop. "The
| loop variable disappears when the loop ends unless the
| loop contains a break".
|
| In my opinion, Python should pick a model and stick to
| it. Loop variables are either ordinary variables that
| exist until you explicitly delete them, or they are
| special variables that automagically disappear at the
| end of the loop. I vote for the first one.

That makes sense to me, but I read "For list comps" as "For list
comprehensions (but not conventional loops.)" List comprehensions
shouldn't need to have every side effect of the equivalent loop.

Donn Cave, do**@drizzle.com
Jul 18 '05 #5

P: n/a
On Thu, 11 Mar 2004 17:54:56 -0700, David MacQuigg <dm*@gain.com>
wrote:
> b=[4,5,6]
> [t*2 for t in b]

[8, 10, 12]
> t

6

Is this anywhere useful, or more of an artifact?


Scopes are defined by the boundaries of functions, classes and
modules, not for loops. This is essential, or you would have to
declare global variables inside most for loops.


I am not following this argument. The surprise, specifically, is
that I don't think of myself as having declared "t" as a variable. it
is don't magically, as a placeholder and for a very specific purpose.
So I would expect it to go away outside of the " [ " and " ] " by
equal and opposite magic.

I ran into the issue while playing at the prompt. Running the same
statement I had run previously gave me a different result than before.
Surprising. Yes I had tested a list comp, in between. Because I have
been around the language for some time, and have my ear to the ground,
it didn't take me long to understand what was happening.

Flabbergasted, rather than surprised, might have otherwise been the
reaction.

Art

Jul 18 '05 #6

P: n/a
<us**@domain.invalid> wrote in message
news:40**************@domain.invalid...
Terry Reedy wrote:
For list comps which cannot have break,
it is an artifact which may disappear in 2.4.


If I understand you,


I don't think you did. The 'may' only applies to list comprehensions. The
discussion last fall was whether the index names(s) within a list
comprehension should be bound outside (after) the list comp. It is
something of an accident of the current implementation that they are. The
issue arose in the development of generator comprehensions, in which it was
clear that the within-generator variables would *not* be bound outside of
the produced generator. Bret Cannon's summary
http://www.python.org/dev/summary/20...-older-brother
is this:

---------------
A quick example is:

(x for x in range(10) if x%2)

returns an iterator that returns the odd numbers from 0 to 10. This make
list comprehensions just syntactic sugar for passing a generator expression
to list() (note how extra parentheses are not needed):

list(x for x in range(10) is x%2)

Having list comprehensions defined this way also takes away the dangling
item variable for the 'for' loop. Using that dangling variable is now
discouraged and will be made illegal at some point.
----------------

Terry J. Reedy


Jul 18 '05 #7

P: n/a
>>>>> "Arthur" == Arthur <aj******@optonline.com> writes:

Arthur> I am not following this argument. The surprise, specifically,
Arthur> is that I don't think of myself as having declared "t" as a
Arthur> variable. it is don't magically, as a placeholder and for a
Arthur> very specific purpose. So I would expect it to go away outside
Arthur> of the " [ " and " ] " by equal and opposite magic.

I remember I've read that this more proper scoping for list comprehension
will take effect in a future version of Python.

Regards,
Isaac.
Jul 18 '05 #8

P: n/a
On Fri, 12 Mar 2004 14:06:38 GMT, Arthur <aj******@optonline.com>
wrote:
On Thu, 11 Mar 2004 17:54:56 -0700, David MacQuigg <dm*@gain.com>
wrote:

Scopes are defined by the boundaries of functions, classes and
modules, not for loops. This is essential, or you would have to
declare global variables inside most for loops.


I am not following this argument. The surprise, specifically, is
that I don't think of myself as having declared "t" as a variable. it
is don't magically, as a placeholder and for a very specific purpose.
So I would expect it to go away outside of the " [ " and " ] " by
equal and opposite magic.


The "declarations" are automatic, whenever you *use* a variable. I
would *not* expect temporary variables in a loop to go away outside of
the loop. It's just another variable in the current namespace.

I think I may have misunderstood your original question. The title of
the thread is 'loop scope', but your question seems to be specifically
on the loop iteration variable 't'. Just think of it as a normal
variable in the current local scope.

The one exception I can think of is what Terry Reedy mentioned - the
iteration variable in a list comprehension. In some future
optimization, they may neglect to save that variable. I hope they
don't do that (even though it really has no use). I just like the
consistency we now have in treatment of all local variables.

-- Dave

Jul 18 '05 #9

P: n/a
In article <kd********************************@4ax.com>,
Arthur <aj******@optonline.com> wrote:
On Thu, 11 Mar 2004 17:54:56 -0700, David MacQuigg <dm*@gain.com>
wrote:
Scopes are defined by the boundaries of functions, classes and
modules, not for loops. This is essential, or you would have to
declare global variables inside most for loops.


I am not following this argument. The surprise, specifically, is
that I don't think of myself as having declared "t" as a variable. it
is don't magically, as a placeholder and for a very specific purpose.
So I would expect it to go away outside of the " [ " and " ] " by
equal and opposite magic.


Well, you don't declare variables in Python. You use
names to refer to objects. Python 2.4 may give each list
comprehension its own namespace, but for now names used in a
list comp. are used just as they would be in any other
statement.

Regards. Mel.
Jul 18 '05 #10

P: n/a
David MacQuigg <dm*@gain.com> writes:
On Fri, 12 Mar 2004 14:06:38 GMT, Arthur <aj******@optonline.com>
wrote:
On Thu, 11 Mar 2004 17:54:56 -0700, David MacQuigg <dm*@gain.com>
wrote:
Scopes are defined by the boundaries of functions, classes and
modules, not for loops. This is essential, or you would have to
declare global variables inside most for loops.

The one exception I can think of is what Terry Reedy mentioned - the
iteration variable in a list comprehension. In some future
optimization, they may neglect to save that variable. I hope they
don't do that (even though it really has no use). I just like the
consistency we now have in treatment of all local variables.


You can maintain that consistency by extending the list of
"boundaries" which define scopes; you already mentioned classes,
functions and modules ... now simply add list comprehensions (or
loops), and you will maintain perfect consistency of treatment of
local variables, without leaking variables out of list comprehensions
(or loops).
Jul 18 '05 #11

P: n/a
On 12 Mar 2004 17:13:19 +0100, Jacek Generowicz
<ja**************@cern.ch> wrote:
David MacQuigg <dm*@gain.com> writes:
On Fri, 12 Mar 2004 14:06:38 GMT, Arthur <aj******@optonline.com>
wrote:
>On Thu, 11 Mar 2004 17:54:56 -0700, David MacQuigg <dm*@gain.com>
>wrote:

>>Scopes are defined by the boundaries of functions, classes and
>>modules, not for loops. This is essential, or you would have to
>>declare global variables inside most for loops.

The one exception I can think of is what Terry Reedy mentioned - the
iteration variable in a list comprehension. In some future
optimization, they may neglect to save that variable. I hope they
don't do that (even though it really has no use). I just like the
consistency we now have in treatment of all local variables.


You can maintain that consistency by extending the list of
"boundaries" which define scopes; you already mentioned classes,
functions and modules ... now simply add list comprehensions (or
loops), and you will maintain perfect consistency of treatment of
local variables, without leaking variables out of list comprehensions
(or loops).


I think the current design of Python is the right compromise between
narrow scopes that avoid conflicts between identical names and broad
scopes that minimize the need for global declarations. Imagine having
to declare globals inside every loop that needed to set some value
outside of its own tiny little scope.

-- Dave

Jul 18 '05 #12

P: n/a

"David MacQuigg" <dm*@gain.com> wrote in message
news:ut********************************@4ax.com...
The one exception I can think of is what Terry Reedy mentioned - the
iteration variable in a list comprehension. In some future
optimization, they may neglect to save that variable. I hope they
don't do that (even though it really has no use). I just like the
consistency we now have in treatment of all local variables.


Please see other post. In the future, the consisitency will be with
generator comprehensions, where the loop variable is clearly encapsulated
inside the induced generator function.

Terry J. Reedy


Jul 18 '05 #13

P: n/a
Jacek Generowicz wrote:
now simply add list comprehensions (or
loops), and you will maintain perfect consistency of treatment of
local variables,


It wouldn't do to make the whole (non-comprehension)
for-loop a new scope, because that would make any
variables assigned within the loop body local as well.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Jul 18 '05 #14

P: n/a
David MacQuigg <dm*@gain.com> writes:
You can maintain that consistency by extending the list of
"boundaries" which define scopes; you already mentioned classes,
functions and modules ... now simply add list comprehensions (or
loops), and you will maintain perfect consistency of treatment of
local variables, without leaking variables out of list comprehensions
(or loops).


I think the current design of Python is the right compromise between
narrow scopes that avoid conflicts between identical names and broad
scopes that minimize the need for global declarations. Imagine having
to declare globals inside every loop that needed to set some value
outside of its own tiny little scope.


And what if the variable I want to affect is in an enclosing scope,
but not the global scope ?

Doesn't this rather suggest that the whole global declaration business
is rather flawed? It sort of made sense when we only had 3 scopes in
Python (only 2 of which were "userland" scopes) , but with nested
scopes it's simply not up to the job. Ultimately, the problem can be
traced to having no distinction between inctroducting a new binding
and rebinding an existing name.
Jul 18 '05 #15

P: n/a
"Greg Ewing (using news.cis.dfn.de)" <wm*******@sneakemail.com> writes:
Jacek Generowicz wrote:
now simply add list comprehensions (or
loops), and you will maintain perfect consistency of treatment of
local variables,


It wouldn't do to make the whole (non-comprehension)
for-loop a new scope, because that would make any
variables assigned within the loop body local as well.


Sometimes you want that, and sometimes you don't. What you need is a
way to distinguish between the two. IOW, you want to distinguish
between creating a new binding, and rebinding. In Python both of these
are spelt thus: "=", and its actual meaning is determied by the
context. With the added spice of the exceptional case of "global".

Imagine (for the sake of brevity of argument --- I wouldn't dream of
suggesting such a "line-noise" syntax for Python) that you could use
"x := 3" to mean "create a new local binding for x", while "x = 3"
would mean "find the innermost x and rebind it", with function
parameters, loop variables, list comprehension variables all behaving
as if they were using ":=". Now you'll find that you gain a lot of
flexibility to do what is appropriate with scopes of variables used in
loops etc., and you have an opportunity to fix the immutability of
closures ...

(Of course there are "issues" ... what happens, for
example when you say

def foo(a):
a := 3
a := 4

.... does that make three nested scopes for a?, is it an error?)
Jul 18 '05 #16

P: n/a
Jacek Generowicz <ja**************@cern.ch> writes:
Imagine (for the sake of brevity of argument --- I wouldn't dream of
suggesting such a "line-noise" syntax for Python) that you could use
"x := 3" to mean "create a new local binding for x", while "x = 3"
would mean "find the innermost x and rebind it", with function
parameters, loop variables, list comprehension variables all behaving
as if they were using ":=". Now you'll find that you gain a lot of
flexibility to do what is appropriate with scopes of variables used in
loops etc., and you have an opportunity to fix the immutability of
closures ...

(Of course there are "issues" ... what happens, for
example when you say

def foo(a):
a := 3
a := 4

... does that make three nested scopes for a?, is it an error?)
Hmm, this is starting to intrigue me.

What are the situations that need disambiguating?

What situations do (or might) create inner scopes?

"def" and "class" are currently the two ways of creating an inner
scope (have I overlooked any others?) ... and we are considering the
possibility of "for" doing the same (in two different flavours: loops
and comprehensions).

Current rules can be summarized as:

In a scope creating block (def, class), assignment introduces a
local binding, unless the name is declared global.

It looks like what's missing (because originally there were no other
scopes between local and global) is some way of declaring a name to
refer to an enclosing scope which may or may not be the global scope.

For example:
def make(): ... x = 0
... def show(): print x
... def inc(n): x = x+n
... return show,inc
... show,inc = make()
show() 0 inc(3)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in inc
UnboundLocalError: local variable 'x' referenced before assignment

The problem is that the "x =" inside "def inc():" tells the compiler
to treat "x" as local to the scope of "inc", and then the reference to
"x" or the RHS of the same line refers to an unbound variable ("x" in
the _local_ scope). "global" is there for exactly this sort of
situation, except that it originates from a time when there were no
nested scopes, so it offers no help if you want to refer to some scope
other than the global or local.

Imagine we have a "nested" keyword which is similar to "global", only
it ensures that the name is found in the nearest enclosing scope. Now
the above problem could be resolved by defining "inc" as follows.

def make():
x = 0
...
def inc(n):
nested x
x = x+n
...

Works just like global would have done, only it is aware of the
other socpes between local and global.
"Greg Ewing (using news.cis.dfn.de)" <wm*******@sneakemail.com> writes:
It wouldn't do to make the whole (non-comprehension)
for-loop a new scope, because that would make any
variables assigned within the loop body local as well.


Not if you have a "nested" keyword at your disposal.

What situations would this not cover ?
Jul 18 '05 #17

P: n/a
On 15 Mar 2004 12:52:14 +0100, Jacek Generowicz
<ja**************@cern.ch> wrote:
Jacek Generowicz <ja**************@cern.ch> writes:
Imagine (for the sake of brevity of argument --- I wouldn't dream of
suggesting such a "line-noise" syntax for Python) that you could use
"x := 3" to mean "create a new local binding for x", while "x = 3"
would mean "find the innermost x and rebind it", with function
parameters, loop variables, list comprehension variables all behaving
as if they were using ":=". Now you'll find that you gain a lot of
flexibility to do what is appropriate with scopes of variables used in
loops etc., and you have an opportunity to fix the immutability of
closures ...

(Of course there are "issues" ... what happens, for
example when you say

def foo(a):
a := 3
a := 4

... does that make three nested scopes for a?, is it an error?)
Hmm, this is starting to intrigue me.

What are the situations that need disambiguating?

What situations do (or might) create inner scopes?

"def" and "class" are currently the two ways of creating an inner
scope (have I overlooked any others?) ... and we are considering the
possibility of "for" doing the same (in two different flavours: loops
and comprehensions).


Is it (entirely) correct to say that class opens a new scope? I don't
think so, since names bound within the class body become attributes of
the class object, they are not local variables -- you can reach them
from the outside.
Current rules can be summarized as:

In a scope creating block (def, class), assignment introduces a
local binding, unless the name is declared global.

It looks like what's missing (because originally there were no other
scopes between local and global) is some way of declaring a name to
refer to an enclosing scope which may or may not be the global scope.

For example:
>>> def make(): ... x = 0
... def show(): print x
... def inc(n): x = x+n
... return show,inc
... >>> show,inc = make()
>>> show() 0 >>> inc(3)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in inc
UnboundLocalError: local variable 'x' referenced before assignment

The problem is that the "x =" inside "def inc():" tells the compiler
to treat "x" as local to the scope of "inc", and then the reference to
"x" or the RHS of the same line refers to an unbound variable ("x" in
the _local_ scope). "global" is there for exactly this sort of
situation, except that it originates from a time when there were no
nested scopes, so it offers no help if you want to refer to some scope
other than the global or local.


There were discussions about this in in the python dev list. The only
proposal that stuck in my memory was an extension of the global
keyword where you had an option of specifying the scope, something
like:

def g(*args):

x = None

def f(*args):
global x in g

The scope of a name is determined at compile time, so it seems
unavoidable that a declaration is needed. But I wished that there were
no declarations in Python and some OO form of treating scopes like
objects with the local names being its attributes were available --
but I am also well aware that this is a very idiosincratic preference
:-)

With my best regards,
G. Rodrigues
Jul 18 '05 #18

P: n/a
Gonçalo Rodrigues <op*****@mail.telepac.pt> writes:
Is it (entirely) correct to say that class opens a new scope? I don't
think so,
class foo: .... a = 3
.... def bar(self):
.... print a
.... f = foo()
f.bar()

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in bar
NameError: global name 'a' is not defined

Bleargh! You are right. Now that you bring it up, I recall bumping up
against it before.
since names bound within the class body become attributes of the
class object, they are not local variables -- you can reach them
from the outside.
That in itself does not prevent "class" from introducing a scope. It
just means that there are ways of getting at things in that scope
.... just like here:

def foo():
a = [3]
def show():
print a[0]
def inc(n):
a[0] += n
return show, inc

show, inc = foo()
show() # prints 3
inc(2)
show() # prints 5

"a" is definitely in the scope introduced by "foo", but you can reach
it from the outside.
There were discussions about this in in the python dev list. The only
proposal that stuck in my memory was an extension of the global
keyword where you had an option of specifying the scope, something
like:

def g(*args):

x = None

def f(*args):
global x in g


Hmmm ... the explicit naming of the scope sort of piddles all over the
elegance of nested scopes. But maybe the generality of being able to
specify *any* enclosing scope has some applications, though none come
to mind immediately.

OTOH:

def g():
x = None
def g():
x = None
def g():
global x in g

Just *which* g are we talking about ?

Let's just stick to finding the innermost binding of the name :-)

Of course, the name "global" is completely inappropriate, but I guess
they're trying to avoid a new keyword.
Jul 18 '05 #19

P: n/a
>
I think I may have misunderstood your original question. The title of
the thread is 'loop scope', but your question seems to be specifically
on the loop iteration variable 't'. Just think of it as a normal
variable in the current local scope.


I can. But it's not my first inclination. And I would speculate I am
far from alone. Having subtleties to be aware of in something as
fundamenatal as a for loop is not a great thing, IMO. On the hand
hand, it was a long time before any subtleties here had any practical
implications to me. I had been getting away with ignorance. But its
not a good feeling to know that.

t=None #(or something)

required prior to a loop would assure I am conscious of what I am
getting myself into. Without it, it seems it isn't safe to assume the
user understands the full implications of simply complying with
required loop syntax.

Wouldn't something like this make sense:

With a loop iteration variable declared explicitly in the curent scope
and prior to the loop, it survives the loop. Otherwise it is treated
as a placeholder within the loop, and goes out of scope at its
conclusion.

All other issues regarding scopes. with loops, are as they are.

No new keywords, no overstating the issue.

But does 't=None' have any meaning in Python now?

I guess if it doesn't anything along the lines of my suggestion
doesn't make much sense.

Art
Jul 18 '05 #20

P: n/a
On Mon, 15 Mar 2004 14:43:20 GMT, Arthur <aj******@optonline.com>
wrote:

I think I may have misunderstood your original question. The title of
the thread is 'loop scope', but your question seems to be specifically
on the loop iteration variable 't'. Just think of it as a normal
variable in the current local scope.


I can. But it's not my first inclination. And I would speculate I am
far from alone. Having subtleties to be aware of in something as
fundamenatal as a for loop is not a great thing, IMO. On the hand
hand, it was a long time before any subtleties here had any practical
implications to me. I had been getting away with ignorance. But its
not a good feeling to know that.

t=None #(or something)

required prior to a loop would assure I am conscious of what I am
getting myself into. Without it, it seems it isn't safe to assume the
user understands the full implications of simply complying with
required loop syntax.

Wouldn't something like this make sense:

With a loop iteration variable declared explicitly in the curent scope
and prior to the loop, it survives the loop. Otherwise it is treated
as a placeholder within the loop, and goes out of scope at its
conclusion.


This is a little too tricky for my taste. Often we need to 'break'
from a loop, and subsequently use the value of 't'. If we forget to
"declare" 't' outside the loop, then we will have a situation where
you get a run-time error if the loop ends without a break.

What is the benefit of keeping 't' out of the surrounding local
scope?" This whole thread seems pointless unless there is a
substantial benefit to changing the current behavior.

-- Dave

Jul 18 '05 #21

P: n/a
In article <j4********************************@4ax.com>,
David MacQuigg <dm*@gain.com> wrote:
On Mon, 15 Mar 2004 14:43:20 GMT, Arthur <aj******@optonline.com>
wrote:
t=None #(or something)

required prior to a loop would assure I am conscious of what I am
getting myself into. Without it, it seems it isn't safe to assume the
user understands the full implications of simply complying with
required loop syntax.

Wouldn't something like this make sense:

With a loop iteration variable declared explicitly in the curent scope
and prior to the loop, it survives the loop. Otherwise it is treated
as a placeholder within the loop, and goes out of scope at its
conclusion.


This is a little too tricky for my taste. Often we need to 'break'
from a loop, and subsequently use the value of 't'. If we forget to
"declare" 't' outside the loop, then we will have a situation where
you get a run-time error if the loop ends without a break.


I didn't read anything there that proposed to make a distinction
between `ends with break' and `ends without break.' That would
be a bad thing.
What is the benefit of keeping 't' out of the surrounding local
scope?" This whole thread seems pointless unless there is a
substantial benefit to changing the current behavior.


Well, the bottom line has to be whether it's easier to
read the code and understand what it does. In a procedural
language like Python, variable scope is critical to that,
so it's important to get it right. Unfortunately, I don't
know if there's a good answer.

Taking list comprehensions, because that's what the original
post took at least as an example and because that's the only
case that is new enough to half seriously consider changing -

t = f(a/c)
... # and then later,
sl = [t * t for t in range(3)]

In this case, I would argue that it's an error for t to escape
the expression scope _because_ it's used outside that scope -
actually I think that was where we came in. My personal view
is that a list comprehension should have its own internal scope,
period, but is that what `intuition' would lead most Python
programmers to expect? I don't know.

Donn Cave, do**@u.washington.edu
Jul 18 '05 #22

P: n/a
On Mon, 15 Mar 2004 10:38:20 -0700, David MacQuigg <dm*@gain.com>
wrote:
On Mon, 15 Mar 2004 14:43:20 GMT, Arthur <aj******@optonline.com>
wrote:

With a loop iteration variable declared explicitly in the curent scope
and prior to the loop, it survives the loop. Otherwise it is treated
as a placeholder within the loop, and goes out of scope at its
conclusion.
This is a little too tricky for my taste.


Mine too, really. But it was off the cuff, and illustrative. And as
I said, the current behavior hasn't caused me any actual problem.
There are probably reasons why one can expect ot get away with being
blissfully ignorant here.

I couldn't/wouldn't do anything with "t", being unaware that it was
there. And if I rebind "t" to something else, its the same as if I
was orignally binding it. No harm, no foul.

Essentailly what happened in the session that brought this up for me
was that I goofed, used "t" without binding it to anything (well
actually I had without realizing) and got a result that I couldn't
make sense of, rather than the error message which I deserved (or
would otherwise have deserved).

I haven't convinced myself it is possible to write sensible code *and*
get caught here, even if unaware of the scoping issue. Though I
haven't convinced myself it isn't, either.

Often we need to 'break'
from a loop, and subsequently use the value of 't'. If we forget to
"declare" 't' outside the loop, then we will have a situation where
you get a run-time error if the loop ends without a break.

What is the benefit of keeping 't' out of the surrounding local
scope?" This whole thread seems pointless unless there is a
substantial benefit to changing the current behavior.

-- Dave


Jul 18 '05 #23

P: n/a
t = f(a/c)
... # and then later,
sl = [t * t for t in range(3)]

In this case, I would argue that it's an error for t to escape
the expression scope _because_ it's used outside that scope -
actually I think that was where we came in. My personal view
is that a list comprehension should have its own internal scope,
period, but is that what `intuition' would lead most Python
programmers to expect? I don't know.


From what I understand, the above case is taken care of in Python 2.4

In the case of:

t = f(a/c)
.... # and then later,
s1 = []
for t in range(3):
s1.append(t * t)

The behavior is unchanged in 2.4, t gets rebound.

- Josiah
Jul 18 '05 #24

P: n/a
On Mon, 15 Mar 2004 10:26:41 -0800, Donn Cave <do**@u.washington.edu>
wrote:

Taking list comprehensions, because that's what the original
post took at least as an example and because that's the only
case that is new enough to half seriously consider changing -

t = f(a/c)
... # and then later,
sl = [t * t for t in range(3)]

In this case, I would argue that it's an error for t to escape
the expression scope _because_ it's used outside that scope -
actually I think that was where we came in.
Yeah, I guess that is where the danger is, if I had been previously
bound "t" and had it rebound against my expectations Which was not
exactly the case I fell into. Thinking about it, I - and hopefully
others - at least have an intuitive sense of knowing what they don't
know.

I guess there were always enough variable names at my disposal that I
have avoided using something as a iterator variable that I have used
for some other purpose in the same scope. Just to be safe. And knowing
I don't fully understand what is happening under the covers.. Good
boy. me.

Art My personal view
is that a list comprehension should have its own internal scope,
period, but is that what `intuition' would lead most Python
programmers to expect? I don't know.

Donn Cave, do**@u.washington.edu


Jul 18 '05 #25

P: n/a
In article <ty*************@pcepsft001.cern.ch>,
Jacek Generowicz <ja**************@cern.ch> wrote:
Imagine we have a "nested" keyword which is similar to "global", only
it ensures that the name is found in the nearest enclosing scope. Now
the above problem could be resolved by defining "inc" as follows.

def make():
x = 0
...
def inc(n):
nested x
x = x+n
...

Works just like global would have done, only it is aware of the
other socpes between local and global.
"Greg Ewing (using news.cis.dfn.de)" <wm*******@sneakemail.com> writes:
> It wouldn't do to make the whole (non-comprehension)
> for-loop a new scope, because that would make any
> variables assigned within the loop body local as well.


Not if you have a "nested" keyword at your disposal.

What situations would this not cover ?


Far too few. After the `nested x` statement comes
`nested nested x` and `nested nested nested x`, with the
accumulating maintenance headaches. All so that programmers
can choose data names badly.

Almost like running into `continue 17` within a nest of
loops.

Regards. Mel.
Jul 18 '05 #26

P: n/a
mw*****@the-wire.com (Mel Wilson) writes:
Far too few. After the `nested x` statement comes
`nested nested x` and `nested nested nested x`,


Nope. You would never write more than one "nested". It would be an
instruction to Python _not_ to treat the name as local, just because
there is an assignment to the name in the local scope. The nearest
scope that has a binding for the name shadows all others ... just like
nested scopes work today. The only problem (today) is that an
assignment to the name creates a binding in the local scope, so there
is no way of _re_-binding a name in an enclosing scope.

Languages which support nested scopes have been around for decades,
and none of them have (to my knowledge) found the need for specifying
which nested scope you want to look in; the nearest one is the one you
want. That's, partly, the point of nested scopes.
Jul 18 '05 #27

P: n/a
In article <ty*************@lxplus059.cern.ch>,
Jacek Generowicz <ja**************@cern.ch> wrote:
mw*****@the-wire.com (Mel Wilson) writes:
Far too few. After the `nested x` statement comes
`nested nested x` and `nested nested nested x`,


Nope. You would never write more than one "nested". It would be an
instruction to Python _not_ to treat the name as local, [ ... ]


Sorry. Bad reading. I came to my senses sometime
yesterday. I don't like the idea of rebinding names
non-locally, but that's taste. Nothing to do with the logic
of your idea.

Regards. Mel.
Jul 18 '05 #28

P: n/a
Jacek Generowicz <ja**************@cern.ch> wrote in message news:<ty*************@pcepsft001.cern.ch>...
[snip]
Imagine (for the sake of brevity of argument --- I wouldn't dream of
suggesting such a "line-noise" syntax for Python) that you could use
"x := 3" to mean "create a new local binding for x", while "x = 3"
would mean "find the innermost x and rebind it", with function
parameters, loop variables, list comprehension variables all behaving
as if they were using ":=". Now you'll find that you gain a lot of
flexibility to do what is appropriate with scopes of variables used in
loops etc., and you have an opportunity to fix the immutability of
closures ...

(Of course there are "issues" ... what happens, for
example when you say

def foo(a):
a := 3
a := 4

... does that make three nested scopes for a?, is it an error?)


One way to avoid this problem is to have an explicit scope-creating
construct instead.

def foo(a):
scope outer:
a = 3
scope inner:
a = 4
print a # prints 4
print outer.a # prints 3
print foo.a # prints the function parameter
print a # inner.a is out of scope, so prints 3
foo.b = 5 # Creates a new function-scope variable.
print b # prints 5
Jul 18 '05 #29

P: n/a
> One way to avoid this problem is to have an explicit scope-creating
construct instead.

def foo(a):
scope outer:
a = 3
scope inner:
a = 4
print a # prints 4
print outer.a # prints 3
print foo.a # prints the function parameter
print a # inner.a is out of scope, so prints 3
foo.b = 5 # Creates a new function-scope variable.
print b # prints 5


Ick. Thank god Python doesn't seem to be heading in this direction.

- Josiah
Jul 18 '05 #30

P: n/a
mw*****@the-wire.com (Mel Wilson) writes:
I don't like the idea of rebinding names non-locally.


Though most languages with nested scopes do exactly that (as far as I
am aware).
Jul 18 '05 #31

P: n/a
da*****@yahoo.com (Dan Bishop) writes:
One way to avoid this problem is to have an explicit scope-creating
construct instead.

def foo(a):
scope outer:
a = 3
scope inner:
a = 4
print a # prints 4
print outer.a # prints 3
print foo.a # prints the function parameter
print a # inner.a is out of scope, so prints 3
foo.b = 5 # Creates a new function-scope variable.
print b # prints 5


I think that the elegance of nested scopes relies on the language
being able to find the innermost scope which contains the given name,
_without_ help from the programmer.

But this relies on being able to distinguish binding from re-binding.
Jul 18 '05 #32

P: n/a
Josiah Carlson <jc******@nospam.uci.edu> wrote in message news:<c3**********@news.service.uci.edu>...
One way to avoid this problem is to have an explicit scope-creating
construct instead.

def foo(a):
scope outer:
a = 3
scope inner:
a = 4
print a # prints 4
print outer.a # prints 3
print foo.a # prints the function parameter
print a # inner.a is out of scope, so prints 3
foo.b = 5 # Creates a new function-scope variable.
print b # prints 5


Ick. Thank god Python doesn't seem to be heading in this direction.


I agree. Just because this was my idea doesn't mean I have to like it ;-)

I'm satified with the scope rules the way they are, except for list comprehensions.
Jul 18 '05 #33

P: n/a
On 19 Mar 2004 12:52:08 -0800, da*****@yahoo.com (Dan Bishop) wrote:
Josiah Carlson <jc******@nospam.uci.edu> wrote in message news:<c3**********@news.service.uci.edu>...
> One way to avoid this problem is to have an explicit scope-creating
> construct instead.
>
> def foo(a):
> scope outer:
> a = 3
> scope inner:
> a = 4
> print a # prints 4
> print outer.a # prints 3
> print foo.a # prints the function parameter
> print a # inner.a is out of scope, so prints 3
> foo.b = 5 # Creates a new function-scope variable.
> print b # prints 5


Ick. Thank god Python doesn't seem to be heading in this direction.


I agree. Just because this was my idea doesn't mean I have to like it ;-)

I'm satified with the scope rules the way they are, except for list comprehensions.


There is one small change I would make. Nested scopes should apply to
*any* nested code, including nested classes. This would make the
rules much simpler and easy to teach.

-- Dave

Jul 18 '05 #34

This discussion thread is closed

Replies have been disabled for this discussion.