Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #100876 > unrolled thread
| Started by | jfong@ms4.hinet.net |
|---|---|
| First post | 2015-12-25 19:06 -0800 |
| Last post | 2015-12-27 17:22 +1100 |
| Articles | 12 — 3 participants |
Back to article view | Back to comp.lang.python
A newbie quesiton: local variable in a nested funciton jfong@ms4.hinet.net - 2015-12-25 19:06 -0800
Re: A newbie quesiton: local variable in a nested funciton Ben Finney <ben+python@benfinney.id.au> - 2015-12-26 14:41 +1100
Re: A newbie quesiton: local variable in a nested funciton jfong@ms4.hinet.net - 2015-12-26 00:56 -0800
Re: A newbie quesiton: local variable in a nested funciton Ben Finney <ben+python@benfinney.id.au> - 2015-12-26 20:37 +1100
Re: A newbie quesiton: local variable in a nested funciton Chris Angelico <rosuav@gmail.com> - 2015-12-26 14:44 +1100
Re: A newbie quesiton: local variable in a nested funciton jfong@ms4.hinet.net - 2015-12-26 01:07 -0800
Re: A newbie quesiton: local variable in a nested funciton Chris Angelico <rosuav@gmail.com> - 2015-12-26 20:49 +1100
Re: A newbie quesiton: local variable in a nested funciton jfong@ms4.hinet.net - 2015-12-26 20:05 -0800
Re: A newbie quesiton: local variable in a nested funciton jfong@ms4.hinet.net - 2015-12-26 20:11 -0800
Re: A newbie quesiton: local variable in a nested funciton Chris Angelico <rosuav@gmail.com> - 2015-12-27 17:32 +1100
Re: A newbie quesiton: local variable in a nested funciton jfong@ms4.hinet.net - 2015-12-27 17:02 -0800
Re: A newbie quesiton: local variable in a nested funciton Chris Angelico <rosuav@gmail.com> - 2015-12-27 17:22 +1100
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-12-25 19:06 -0800 |
| Subject | A newbie quesiton: local variable in a nested funciton |
| Message-ID | <d070aa0d-e80f-4efb-a424-351737ddb2fc@googlegroups.com> |
As a tranditional language programmer like me, the result is really weird.
Here is the test codes in file test1.py:
--------
def outerf():
counter = 55
def innerf():
print(counter)
#counter += 1
return innerf
myf = outerf()
--------
the result is:
--------
>>> import test1
>>> test1.myf()
55
>>>
--------
that's OK. But if I un-comment the line "counter += 1", then it gives me this:
--------
>>> import test1
>>> test1.myf()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "D:\Work\Python34\test1.py", line 41, in innerf
print(counter)
UnboundLocalError: local variable 'counter' referenced before assignment
>>>
--------
In the first situation, the local variable 'counter' can be referenced correctly. But in the second, why a statement added after the print() statement can makes this variable "disappear", even the print() won't do the right thing. Isn't it wired? please help!
[toc] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2015-12-26 14:41 +1100 |
| Message-ID | <mailman.16.1451101299.11925.python-list@python.org> |
| In reply to | #100876 |
jfong@ms4.hinet.net writes: > In the first situation, the local variable 'counter' can be referenced > correctly. But in the second, why a statement added after the print() > statement can makes this variable "disappear", even the print() won't > do the right thing. Isn't it wired? please help! The Python FAQ answers this, even using an example the same as yours <URL:https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value>. -- \ “… a Microsoft Certified System Engineer is to information | `\ technology as a McDonalds Certified Food Specialist is to the | _o__) culinary arts.” —Michael Bacarella | Ben Finney
[toc] | [prev] | [next] | [standalone]
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-12-26 00:56 -0800 |
| Message-ID | <ffcd67b4-365b-44bb-87c1-38ff3f49d5ef@googlegroups.com> |
| In reply to | #100877 |
Ben Finney at 2015/12/26 UTC+8 11:42:08AM wrote: > The Python FAQ answers this, even using an example the same as yours > <URL:https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value>. > Thank you, Ben. It's amazing that you seem to know every piece of Python information hiding in the web:-) see this question listed in python core language's Q&A makes me feel better for I am not the only one who commit this kind of crime. I should read this Q&A throughly before going any further. --Jach
[toc] | [prev] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2015-12-26 20:37 +1100 |
| Message-ID | <mailman.18.1451122658.11925.python-list@python.org> |
| In reply to | #100882 |
jfong@ms4.hinet.net writes: > Thank you, Ben. It's amazing that you seem to know every piece of > Python information hiding in the web:-) You're welcome, I'm glad to help. As for the “hiding”, the answer is in the Python documentation itself. > see this question listed in python core language's Q&A makes me feel > better for I am not the only one who commit this kind of crime. Never feel embarrassed of not knowing something; we should all be active on the edge of our own ignorance. The embarrassment would be in not seeking to improve our understanding. > I should read this Q&A throughly before going any further. Searching in the official documentation, and in archives of community forums, is an essential skill to learn for a programmer. I wish you good fortune in improving that skill :-) -- \ “Nothing is more sacred than the facts.” —Sam Harris, _The End | `\ of Faith_, 2004 | _o__) | Ben Finney
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-12-26 14:44 +1100 |
| Message-ID | <mailman.17.1451101449.11925.python-list@python.org> |
| In reply to | #100876 |
On Sat, Dec 26, 2015 at 2:06 PM, <jfong@ms4.hinet.net> wrote:
> As a tranditional language programmer like me, the result is really weird.
By "traditional", I'm guessing you mean that you know C-like languages
(Java, ECMAScript/JavaScript, etc). In C, and in many languages
derived from or inspired by it, variable scoping is defined by
declarations that say "here begins a variable".
> Here is the test codes in file test1.py:
> --------
> def outerf():
> counter = 55
> def innerf():
> print(counter)
> #counter += 1
> return innerf
>
> myf = outerf()
Pike is semantically very similar to Python, but it uses C-like
variable scoping. Here's an equivalent, which might help with
comprehension:
function outerf()
{
int counter = 55;
void innerf()
{
write("%d\n", counter);
int counter;
counter += 1;
}
return innerf;
}
Based on that, I think you can see that having a variable declaration
in the function turns things into nonsense. What you're actually
wanting here is to NOT have the "int counter;" line, such that the
name 'counter' refers to the outerf one.
In Python, assignment inside a function creates a local variable,
unless you declare otherwise. To make your example work, all you need
is one statement:
nonlocal counter
That'll cause the name 'counter' inside innerf to refer to the same
thing as it does in outerf.
Hope that helps!
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-12-26 01:07 -0800 |
| Message-ID | <701dd0e6-a9c1-4aa9-a3a2-6607cd3f3759@googlegroups.com> |
| In reply to | #100878 |
Chris Angelico at 2015/12/26 UTC+8 11:44:21AM wrote:
> Pike is semantically very similar to Python, but it uses C-like
> variable scoping. Here's an equivalent, which might help with
> comprehension:
>
> function outerf()
> {
> int counter = 55;
> void innerf()
> {
> write("%d\n", counter);
> int counter;
> counter += 1;
> }
> return innerf;
> }
Hi! ChrisA, this is the first time I hear the name "Pike" programming language:-)
> Based on that, I think you can see that having a variable declaration
> in the function turns things into nonsense. What you're actually
> wanting here is to NOT have the "int counter;" line, such that the
> name 'counter' refers to the outerf one.
>
> In Python, assignment inside a function creates a local variable,
> unless you declare otherwise. To make your example work, all you need
> is one statement:
>
> nonlocal counter
>
> That'll cause the name 'counter' inside innerf to refer to the same
> thing as it does in outerf.
Thank you for the explanation. It reminds me to dig out something which seems I had been read before. It's about nested scope in the book "Learning Python" by Mark Lutz.
"An assignment (X = value) creates or changes the name X in the current local
scope, by default. If X is declared global within the function, the assignment creates or changes the name X in the enclosing module's scope instead. If, on the other hand, X is declared nonlocal within the function in 3.X (only), the assignment changes the name X in the closest enclosing function's local scope."
I shouldn't forget this:-(
> Hope that helps!
You have a correct answer. Thanks again.
--Jach
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-12-26 20:49 +1100 |
| Message-ID | <mailman.19.1451123395.11925.python-list@python.org> |
| In reply to | #100884 |
On Sat, Dec 26, 2015 at 8:07 PM, <jfong@ms4.hinet.net> wrote:
> Thank you for the explanation. It reminds me to dig out something which seems I had been read before. It's about nested scope in the book "Learning Python" by Mark Lutz.
>
> "An assignment (X = value) creates or changes the name X in the current local
> scope, by default. If X is declared global within the function, the assignment creates or changes the name X in the enclosing module's scope instead. If, on the other hand, X is declared nonlocal within the function in 3.X (only), the assignment changes the name X in the closest enclosing function's local scope."
>
Yep! That's an accurate description of how assignment works.
One of the cool things about Python is that there are all sorts of
things that work _exactly_ the same way. Every one of these statements
is a form of assignment:
import json # 1
from sys import argv # 2
def testfiles(files): # 3, 4
failures = 0 # 5
for file in files: # 6
with open(file) as fp: # 7
try: data = json.load(fp) # 8
except JSONDecodeError as err: # 9
failures += 1 # 10
return failures
count = testfiles(argv) # 11
Okay, every one except the 'return' statement. :)
1: "import x" is basically the same as "x = __import__('x')".
2: "from x import y" is basically "y = __import__('x').y" (more or
less). This grabs "sys.argv" and assigns it to the name "argv".
3: Defining a function constructs a new function object and assigns it
to the name. This is like doing "testfiles = <magic>".
4: As the function gets called, a new scope is created, and inside
that scope, the interpreter does the equivalent of "files = <magic>",
where the magic snags a reference to whatever was used as the argument
(so this is basically "files = argv").
5: That's straight-forward assignment, right there.
6: A 'for' loop grabs an iterator, then repeatedly does "file =
next(iterator)" until there's nothing more to do.
7: A 'with' statement does some work, and then does "fp = <result of
that work>" if it has an 'as' clause.
8: Another straight-forward assignment, because I couldn't think of
anything better to use. (Normally you'd lay this out with 'try:' on a
separate line, but then I'd have had a line without any assignment at
all.)
9: Like a 'with' statement, 'except' assigns to its name. There's a
special case here, in that it also does 'del err' at the end of the
except block, to clean stuff up; but it's still just assignment.
10: Augmented assignment is assignment too. x+=1, x-=1, x*=1, etc, are
all assigning to x.
11: Another normal assignment, because otherwise the rest of the work
is pointless. :)
Every one of these follows the standard rules for assignment. For
instance, you could create a function that does a top-level import:
$ python3
Python 3.6.0a0 (default:6e114c4023f5, Dec 20 2015, 19:15:28)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def do_imports():
... global os, sys, json
... import os, sys, json
...
>>> do_imports()
>>> json
<module 'json' from '/usr/local/lib/python3.6/json/__init__.py'>
You wouldn't normally do this for standard modules like 'os' and
'sys', but if you have something huge to load up (like pandas, or
oauth2client), it might be convenient to use them globally, but load
them conditionally. Since 'import' is a statement, not a declaration,
you can do this!
Python's flexibility and simplicity are a huge part of why I love the
language so much.
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-12-26 20:05 -0800 |
| Message-ID | <661a13a1-8084-41ca-b458-297462dc3367@googlegroups.com> |
| In reply to | #100886 |
Chris Angelico at 2015/12/26 UTC+8 5:50:07PM wrote: > 11: Another normal assignment, because otherwise the rest of the work > is pointless. :) Thanks for this detailed example. As I had learned so far, Python really take "name" seriously, and every meaningful result you got have to assign to a name at last. This morning I played some codes on the http://pythonturor.com and found out that every objects which was not created at top-level of a module or in a class will disappear after import. A very "unusual" view. > Python's flexibility and simplicity are a huge part of why I love the > language so much. simplicity? Maybe because you are soooo familiar with Python. It's not to me, at least at this moment. Please see my next question follows. --Jach
[toc] | [prev] | [next] | [standalone]
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-12-26 20:11 -0800 |
| Message-ID | <0bf611ba-c4d9-4465-8d61-6a94bcee79a4@googlegroups.com> |
| In reply to | #100900 |
Last night I noticed that Python does not resolve name in "def" during import, as C does in the compile/link stage, it was deferred until it was referenced (i.e. codes was executed). That's OK for Anyway codes has to be debugged sooner or later. I just have to get used to this style.
But check these codes, it seems not.
-------
x = 1 # a global variable
print(x)
class Test:
x = 4 # a class attribute
print(x)
def func(self):
print(x)
x1 = Test()
x1.x = 41 # a instance's attribute
x1.func() # it's 1 but 41 was expect:-(
--------
--Jach
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-12-27 17:32 +1100 |
| Message-ID | <mailman.27.1451197940.11925.python-list@python.org> |
| In reply to | #100901 |
On Sun, Dec 27, 2015 at 3:11 PM, <jfong@ms4.hinet.net> wrote: > Last night I noticed that Python does not resolve name in "def" during import, as C does in the compile/link stage, it was deferred until it was referenced (i.e. codes was executed). That's OK for Anyway codes has to be debugged sooner or later. I just have to get used to this style. > > But check these codes, it seems not. > ------- > x = 1 # a global variable > print(x) > > class Test: > x = 4 # a class attribute > print(x) > def func(self): > print(x) > > x1 = Test() > x1.x = 41 # a instance's attribute > x1.func() # it's 1 but 41 was expect:-( > -------- > > --Jach When you import this module, it runs all top-level code. So the 'print' at the top will happen at import time. Among the top-level statements is a class definition. When that gets run (to construct the class itself - distinct from instantiating it, which happens further down), it builds a class by executing all the statements in it, in order. That results in that value of x being printed, and then defines a function. The function definition is being run at time of class construction, and it creates a new attribute on the Test class. At that time, the function body isn't actually executed (as you might expect). However, it's worth noting that the function does not inherit class scope. The unadorned name 'x' references the global. If you want to access class-scope names from inside methods, you need to say 'self.x', which also applies to instance attributes. That's what would do what you expect here. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-12-27 17:02 -0800 |
| Message-ID | <fa863fcb-1bbf-45ba-9b70-62c408f94856@googlegroups.com> |
| In reply to | #100903 |
Chris Angelico at 2015/12/27 UTC+8 2:32:32PM wrote: > On Sun, Dec 27, 2015 at 3:11 PM, <jfong@ms4.hinet.net> wrote: > > Last night I noticed that Python does not resolve name in "def" during import, as C does in the compile/link stage, it was deferred until it was referenced (i.e. codes was executed). That's OK for Anyway codes has to be debugged sooner or later. I just have to get used to this style. > > > > But check these codes, it seems not. > > ------- > > x = 1 # a global variable > > print(x) > > > > class Test: > > x = 4 # a class attribute > > print(x) > > def func(self): > > print(x) > > > > x1 = Test() > > x1.x = 41 # a instance's attribute > > x1.func() # it's 1 but 41 was expect:-( > > -------- > > > > --Jach > > When you import this module, it runs all top-level code. So the > 'print' at the top will happen at import time. > > Among the top-level statements is a class definition. When that gets > run (to construct the class itself - distinct from instantiating it, > which happens further down), it builds a class by executing all the > statements in it, in order. That results in that value of x being > printed, and then defines a function. > > The function definition is being run at time of class construction, > and it creates a new attribute on the Test class. At that time, the > function body isn't actually executed (as you might expect). However, > it's worth noting that the function does not inherit class scope. The > unadorned name 'x' references the global. If you want to access > class-scope names from inside methods, you need to say 'self.x', which > also applies to instance attributes. That's what would do what you > expect here. > > ChrisA Yea, right, it's in a method, not a function. A stupid mistake I had made:-( Thanks for your kindly patient with me, and Happy New Year to you:-) --Jach
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-12-27 17:22 +1100 |
| Message-ID | <mailman.26.1451197757.11925.python-list@python.org> |
| In reply to | #100900 |
On Sun, Dec 27, 2015 at 3:05 PM, <jfong@ms4.hinet.net> wrote: >> Python's flexibility and simplicity are a huge part of why I love the >> language so much. > > simplicity? Maybe because you are soooo familiar with Python. It's not to me, at least at this moment. Please see my next question follows. > I define "simplicity" in terms of the number and complexity of the rules you have to keep in your head. It's not necessarily the best thing to do; for instance, a C-style #include directive is *extremely* simple (it is literally "drop the file contents in at this location"), but I prefer Python's semantics. On the other hand, PHP's include directive is *not* simple; in many ways it behaves like C's #include, but it can't be used inside class definitions, and if used in a function, some of what it does is at top level and some is inside the function. Python's rules for imports (whether they're "import X" or "from X import Y") include a somewhat complicated definition of search path, but ultimately, it's a matter of hunting down a module and executing it (all of it) in its own namespace, and then giving you a reference to sys.modules["X"] (or sys.modules["X"].Y for a from-import). ChrisA
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web