473,761 Members | 8,813 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Nested scopes, and augmented assignment

Hi,

The following might be documented somewhere, but it hit me unexpectedly
and I couldn't exactly find this in the manual either.

Problem is, that I cannot use augmented assignment operators in a
nested scope, on variables from the outer scope:

PythonWin 2.4.3 (#69, Mar 29 2006, 17:35:34) [MSC v.1310 32 bit
(Intel)] on win32.
Portions Copyright 1994-2004 Mark Hammond (mh******@skipp inet.com.au) -
see 'Help/About PythonWin' for further copyright information.
>>def foo():
.... def nestedfunc(bar) :
.... print bar, ';', localvar
.... localvar += 1
.... localvar=0
.... nestedfunc('bar ')
....
>>foo()
bar =Traceback (most recent call last):
File "<interacti ve input>", line 1, in ?
File "<interacti ve input>", line 6, in foo
File "<interacti ve input>", line 3, in nestedfunc
UnboundLocalErr or: local variable 'localvar' referenced before
assignment
>>>
This is entirely counter-intuitive to me, and searching the manual for
nested scoping rules and for augmented assignment rules, I still feel
that I couldn't have predicted this from the docs.

Is this an implementation artifact, bug, or should it really just
follow logically from the language definition?

Regards,

--Tim

Jul 4 '06
37 2789
On 2006-07-07, Terry Reedy <tj*****@udel.e duwrote:
>
"Antoon Pardon" <ap*****@forel. vub.ac.bewrote in message
news:sl******** ************@rc pc42.vub.ac.be. ..
>And if Nested variables are harmfull,

I don't know if anyone said that they were, but Guido obviously does not
think so, or he would not have added them. So skip that.
>what is then the big difference between rebinding them and mutating them

A variable is a name. Name can be rebound (or maybe not) but they cannot
be mutated. Only objects (with mutation methods) can be mutated. In other
words, binding is a namespace action and mutation is an objectspace action.
In Python, at least, the difference is fundamental.

Or, in other other words, do not be fooled by the convenient but incorrect
abbreviated phrase 'mutate a nested variable'.
I'm not fooled by that phrase. I just think the mutate vs rebind
explanation is not complete.

If we have two statements "a = b" and "c.d = b" the fact that a is being
rebound while c is mutated doesn't explain why we allow c to be searched
out of the local scope.

By only stating that the first statement is a rebinding and the second
is a mutation and that this is a fundamental difference in python you
seem to suggest that this fundamental differenence implies this
difference in searching scopes. Python could have made the choice
that in an assignment the variable on the left side was always to
be searched in local space so that code like the following would
throw: UnboundLocalErr or: local variable 'c' referenced before assignment

c = SomeObject
def f():
c.a = 5

Now I'm not arguing python should have made this choice. But the
possibility shows IMO this has more to do with search policies
of names than with the distinction between a rebinding and a mutation.

AFAIK when nested scopes where introduced everyone agreed that scopes
had to have access to outer scopes. There were voices that supported
allowing a rebinding in an outer scope but no consensus on how to
do this was reached, so this possibility was dropped. So we can't
rebind an outer scope variable but we can mutate such a variable
because for mutation we only need access.
>I understand that python evolved and that this sometimes results
in things that in hindsight could have been done better.

So does Guido. That is one explicit reason he gave for not choosing any of
the nunerous proposals for the syntax and semantics of nested scope write
access. In the face of anti-consensus among the developers and no
particular personal preference, he decided, "Better to wait than roll the
dice and make the wrong, hard to reverse, choice now". (Paraphrased quote)
>>I have to wonder if someone really thought this through at design time

Giving the actual history of, if anything, too many people thinking too
many different thoughts, this is almost funny.
Maybe I didn't made myself clear enough, but I never meant to imply
people hadn't thought thouroughly about this. If I gave you this
impression I appologize. What I was wondering about was that those
that had thought about it, would have reached a certain conclusion
that seemed suggested.
Recently however, Guido has rejected most proposals to focus attention on
just a few variations and possibly gain a consensus. So I think there is
at least half a chance that some sort of nested scope write access will
appear in 2.6 or 3.0.
Well I have browsed the discussion, which is why I react so lately to
this, and there is one thing I wonder about. As far as I can see no
suggestion removes the difference in the default search. The following
code will still work and won't need an outer statement. (or global,
nonlocal or whatever it will be)

c = SomeObject
def f():
c.a = 5

I don say they have to change this, but since it seemed decided this
was a python3k thing, i think the question deserved to be raised.

But I'm glad with this turn of events anyhow.

Just my 2 cent.

--
Antoon Pardon
Jul 8 '06 #31
On 2006-07-07, Piet van Oostrum <pi**@cs.uu.nlw rote:
>>>>>Antoon Pardon <ap*****@forel. vub.ac.be(AP) wrote:
>>APOn 2006-07-07, Piet van Oostrum <pi**@cs.uu.nlw rote:
>>>>>>>>Antoo n Pardon <ap*****@forel. vub.ac.be(AP) wrote:
APCould you maybe clarify what problem we are discussing? All I wrote
APwas that with an assignment the search for the lefthand variable
APdepends on whether the lefthand side is a simple variable or
APmore complicated.
>>>>
What do you mean with `the lefthand variable'? Especially when talking
about `complicated lefthand sides'?
>>APThe name on the left side of an assignment that refers to a variable,
APas opposed to names that are attributes.

So let me get it clear:
In a.b = c, a is the lefthand variable, but b is not?
Yes, b is an attribute of a
If that is what you mean then I interpret your statement
>>AP`with an assignment the search for the lefthand variable
APdepends on whether the lefthand side is a simple variable or
APmore complicated'

as meaning that the search for `a' in `a.b = c' would be different than the
search for `a' in `a = b'.
It is conceptually different. In the line 'a = b' you don't need to
search for the scope of a. You know it is the current scope, if you
want to know the scope of b on the other hand, you need to search
for statement where it is assigned to.

Sure you can set things up in the interpreter so that the same search
routine is used, but that is IMO an implementation detail.
Well, it is not. But I can understand the
confusion. Namely, `a = b' introduces a binding for `a' in the local scope,
unless `a' was declared global. So the search will find `a' in the local
scope and it stops there. On the other hand `a.b = c' will not introduce a
binding for `a'. So the search for `a' may stop in the local space (if
there was another binding for `a' in the local scope) or it may need to
continue to outer scopes. The difference, however is not the
complicatedness of the lefthand side but whether the local scope contains a
binding for the variable.
The complicatedness of the lefthand side, decided on whether the
variable was introduced in the local scope or not during startup
time. So that complicatedness decided whether the search was
to stop at the local level or not.

--
Antoon Pardon
Jul 8 '06 #32
>>>>Antoon Pardon <ap*****@forel. vub.ac.be(AP) wrote:
>APIt is conceptually different. In the line 'a = b' you don't need to
APsearch for the scope of a. You know it is the current scope, if you
Except when it has been declared global.
>APwant to know the scope of b on the other hand, you need to search
APfor statement where it is assigned to.
>APSure you can set things up in the interpreter so that the same search
AProutine is used, but that is IMO an implementation detail.
>>Well, it is not. But I can understand the
confusion. Namely, `a = b' introduces a binding for `a' in the local scope,
unless `a' was declared global. So the search will find `a' in the local
scope and it stops there. On the other hand `a.b = c' will not introduce a
binding for `a'. So the search for `a' may stop in the local space (if
there was another binding for `a' in the local scope) or it may need to
continue to outer scopes. The difference, however is not the
complicatedne ss of the lefthand side but whether the local scope contains a
binding for the variable.
>APThe complicatedness of the lefthand side, decided on whether the
APvariable was introduced in the local scope or not during startup
APtime. So that complicatedness decided whether the search was
APto stop at the local level or not.
No, it doesn't. There could be another binding in the same scope. The
complicatedness of this particular assignment doesn't decide anything about
how to search for 'a', but rather the presence or absence of a binding
anywhere in the scope.
--
Piet van Oostrum <pi**@cs.uu.n l>
URL: http://www.cs.uu.nl/~piet [PGP 8DAE142BE17999C 4]
Private email: pi**@vanoostrum .org
Jul 9 '06 #33
On 2006-07-09, Piet van Oostrum <pi**@cs.uu.nlw rote:
>>>>>Antoon Pardon <ap*****@forel. vub.ac.be(AP) wrote:
>>APIt is conceptually different. In the line 'a = b' you don't need to
APsearch for the scope of a. You know it is the current scope, if you

Except when it has been declared global.
Yes, I ignored that possibilitym because as far as I understood we
were discussing variables in intermediate scopes.
>>APwant to know the scope of b on the other hand, you need to search
APfor statement where it is assigned to.
>>APSure you can set things up in the interpreter so that the same search
AProutine is used, but that is IMO an implementation detail.
>>>Well, it is not. But I can understand the
confusion. Namely, `a = b' introduces a binding for `a' in the local scope,
unless `a' was declared global. So the search will find `a' in the local
scope and it stops there. On the other hand `a.b = c' will not introduce a
binding for `a'. So the search for `a' may stop in the local space (if
there was another binding for `a' in the local scope) or it may need to
continue to outer scopes. The difference, however is not the
complicatedn ess of the lefthand side but whether the local scope contains a
binding for the variable.
>>APThe complicatedness of the lefthand side, decided on whether the
APvariable was introduced in the local scope or not during startup
APtime. So that complicatedness decided whether the search was
APto stop at the local level or not.
No, it doesn't. There could be another binding in the same scope.
Indeed there could be. But I hoped you would understand I was just
keeping things simple, with a simple example.
The
complicatedness of this particular assignment doesn't decide anything about
how to search for 'a', but rather the presence or absence of a binding
anywhere in the scope.
I'll word it differently. If the compiler encounters a line like 'a = b'
then you know from that line alone that the search space for a will be
limited to the local scope. If you encounter a line like 'a.c = b' then
you have no such knowledge. A line like 'a = b' will cause the compilor
that at call time variable a will be added to the local scope, a line like
'a.c = b' will not have that effect. So a line like 'a = b' has an
influence on what the search space is for variable a, while a line
like 'a.c = b' doesn't. So the complicatedness on the leftside decides
whether or not the compilor will take certain actions with regards to
the search space of the variable on the left side.

And yes I'm again ignoring global.

--
Antoon Pardon
Jul 9 '06 #34
On 2006-07-08, Dennis Lee Bieber <wl*****@ix.net com.comwrote:
On 8 Jul 2006 18:52:56 GMT, Antoon Pardon <ap*****@forel. vub.ac.be>
declaimed the following in comp.lang.pytho n:

>>
I'm not fooled by that phrase. I just think the mutate vs rebind
explanation is not complete.

If we have two statements "a = b" and "c.d = b" the fact that a is being
rebound while c is mutated doesn't explain why we allow c to be searched
out of the local scope.
The "search" is not different, per se... It is only after the object
is found that the difference becomes apparent -- a rebinding changes an
object's ID, and is not permitted for a non-local UNLESS a "global"
statement appears before any usage of the name.

"c.d =..." has absolutely no effect on the ID of object C; in that
aspect it is a read-only look-up of "c". IOWs, the same look-up as would
be used if "c" were on the RHS of the statement.
>be searched in local space so that code like the following would
throw: UnboundLocalErr or: local variable 'c' referenced before assignment

c = SomeObject
def f():
c.a = 5
What would you say the behavior should be for:

c.a = c.b
vs
la = c.b

The look-up of "c" is the same on both sides of the statement; local
(not found) then global (found), THEN the operation is applied. On both
sides "c" is a read-only look-up (that is, no changes to the ID of "c"
-- no rebinding -- take place).

Are you suggesting we need to use "global c" in order to have "c.b"
on the RHS? By that logic, we would also need "global sys" to reference
"sys.argv" inside a function definition. Remember -- the modules loaded
by "import" are just more "SomeObject " samples...
I think you are misunderstandin g what I was getting at. This example was
not meant to illustrate how I think python should behave. I thought I
had made that clear.

When someone gets confused over the difference between rebinding or mutating
a variable on an intermediate scope, the explanation he mostly seems to get
boils down to: one is rebinding, the other is mutation, this is a fundametal
difference in python.

My impression is that they seem to say that the fundamental difference
between mutation and rebinding implies the specific behaviour python
has now. IMO this explanation is incomplete. The python developers
could have chosen that a line like 'c.a = ...' would have resulted
in c being included in the local scope. Then rebinding and mutation
would still be fundamentally different from each other but the specific
confusion over why 'k[0] = ...' worked as expeced but 'k = ...' didn't,
will disappear.

So I only used this example as an illustration why I think the usual
explanation is not completed. This example is not to be taken as an
illustration of how I think python should behave.

--
Antoon Pardon
Jul 9 '06 #35
>>>>Antoon Pardon <ap*****@forel. vub.ac.be(AP) wrote:
>APWhen someone gets confused over the difference between rebinding or
APmutating a variable on an intermediate scope, the explanation he
APmostly seems to get boils down to: one is rebinding, the other is
APmutation, this is a fundametal difference in python.
>APMy impression is that they seem to say that the fundamental difference
APbetween mutation and rebinding implies the specific behaviour python
APhas now. IMO this explanation is incomplete. The python developers
APcould have chosen that a line like 'c.a = ...' would have resulted
APin c being included in the local scope. Then rebinding and mutation
APwould still be fundamentally different from each other but the specific
APconfusion over why 'k[0] = ...' worked as expeced but 'k = ...' didn't,
APwill disappear.
That seems nonsense to me. If they had chosen that 'c.a = ...' would imply
that c would become a local variable, what would the value of c have to be
then, if there was no prior direct assignment to c? Would it become a new
binding like in 'c = ...'? From what class should it become an instance? Or
would it become a copy of the value that 'c' has in an outer scope? I don't
know any programming language where an assignment to c.a does create a new
c, rather than modifying the existing value of c. That would have been a
very strange language design. Similarly for 'k[0] = ...'. What would happen
with the other elements of k?

There are no situations in Python where an assignment to c.a or c[0]
suddenly lets spring c into existence. You always need an already existing
binding for c for this to be valid. And it always uses that binding, and
doesn't move or copy it to a different block.

Some of the confusing originates from the fact that assignment in Python is
subtly different from assignment in other programming languages. In most
languages variables denote memory locations or collections of memory
locations. An assignment then means changing the contents of those memory
locations. In python variables are bound to values, and assignment means
(re)binding the name to a possibly different value. With an example: most
other languages have boxes with the name of the variable on them. An
assignment changes the contents of the box. In Python you have values
(objects) and an assignment means sticking a label with the name of the
variable on the object. Often the difference is unnoticable, but there are
subtle cases where this really makes a difference.

When the lefthandside of an assignment is an object attribute, subscription
or slice then the assignment is syntactic sugar for a mutation operation
implemented by the object, which usually changes the value of the object
but could do something completely different.

(Finally, the lefthandside can also be a [nested] tuple or list, in which
case it is a collection of parallel assignments. And oh yes, there are also
other binding operations e.g. a function or class definition.)
--
Piet van Oostrum <pi**@cs.uu.n l>
URL: http://www.cs.uu.nl/~piet [PGP 8DAE142BE17999C 4]
Private email: pi**@vanoostrum .org
Jul 9 '06 #36
This is probably my last response to you in this thread. My impression
is that for the moment nothing productive can come from this exchange.
I have the feeling that you are not reading so much with the interntion
of understanding what I want to say, but with the intention of
confirming your suspition that I just don't have a clue.

It seems this is turing into some competition where I have
somehow to defend my understanding of python an you trying to
show how little I really understand. Since I don't feel the
need to prove myself here, I will simply bow out.

On 2006-07-09, Piet van Oostrum <pi**@cs.uu.nlw rote:
>>>>>Antoon Pardon <ap*****@forel. vub.ac.be(AP) wrote:
>>APWhen someone gets confused over the difference between rebinding or
APmutating a variable on an intermediate scope, the explanation he
APmostly seems to get boils down to: one is rebinding, the other is
APmutation, this is a fundametal difference in python.
>>APMy impression is that they seem to say that the fundamental difference
APbetween mutation and rebinding implies the specific behaviour python
APhas now. IMO this explanation is incomplete. The python developers
APcould have chosen that a line like 'c.a = ...' would have resulted
APin c being included in the local scope. Then rebinding and mutation
APwould still be fundamentally different from each other but the specific
APconfusion over why 'k[0] = ...' worked as expeced but 'k = ...' didn't,
APwill disappear.

That seems nonsense to me. If they had chosen that 'c.a = ...' would imply
that c would become a local variable, what would the value of c have to be
then, if there was no prior direct assignment to c?
I'm sorry to see you missed it, but since I had answered this already in
this thread I saw at the moment no need to repeat it: There would be no
value for c, the line would raise an UnboundLocalErr or.

I also don't understand why you take the trouble of attacking this
possibility. It's wasn't presented as a suggestion for changing python.
It was used as an illustration of why I think some explanation needs
to be worked out more. So even if this turns out to be the worst
possible that could ever happen to python, unless you think people
needing the original explanation will grasp the implication of this
possibility immediately, the point I wanted to illustrate seems to
stand.

--
Antoon Pardon
Jul 10 '06 #37
>>>>Antoon Pardon <ap*****@forel. vub.ac.be(AP) wrote:
>API'm sorry to see you missed it, but since I had answered this already in
APthis thread I saw at the moment no need to repeat it: There would be no
APvalue for c, the line would raise an UnboundLocalErr or.
OK. That could have been chosen. But that would mean that instead of c.a =
b, where c is bound in a non-local scope, you have to write something like:

cc = c
cc.a = b

I don't find that useful.
--
Piet van Oostrum <pi**@cs.uu.n l>
URL: http://www.cs.uu.nl/~piet [PGP 8DAE142BE17999C 4]
Private email: pi**@vanoostrum .org
Jul 10 '06 #38

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
2040
by: Doug Tolton | last post by:
I have a function that returns a tuple: def checkdoc(self, document): blen = document bates = document normal, truncated, semicolon = 0,0,0 for bat in bates: if len(bat) == 2 * blen: semicolon += 1
3
2343
by: Nils Grimsmo | last post by:
hi, i'm having some trouble nesting functions. consider the following: def h(): x = 1 def g(): print x # ok, x is taken from h g()
6
2569
by: Andy Baker | last post by:
Hi there, I'm learning Python at the moment and trying to grok the thinking behind it's scoping and nesting rules. I was googling for nested functions and found this Guido quote: (http://www.python.org/search/hypermail/python-1993/0343.html) "This is because nested function definitions don't have access to the local variables of the surrounding block -- only to the globals of the
5
1807
by: Dave Benjamin | last post by:
I ran into an odd little edge case while experimenting with functions that create classes on the fly (don't ask me why): >>> def f(x): ... class C(object): ... x = x ... print C.x ... >>> f(5) Traceback (most recent call last):
4
1529
by: Pierre Barbier de Reuille | last post by:
Hello, a discussion began on python-dev about this. It began by a bug report, but is shifted and it now belongs to this discussion group. The problem I find with augmented assignment is it's too complex, it's badly explained, it's error-prone. And most of all, I don't see any use-case for it ! The most common error is to consider that :
0
9376
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9988
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9923
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8813
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7358
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6640
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5266
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5405
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
2788
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.