Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #83627 > unrolled thread
| Started by | John Ladasky <john_ladasky@sbcglobal.net> |
|---|---|
| First post | 2015-01-12 12:25 -0800 |
| Last post | 2015-01-13 07:51 +1100 |
| Articles | 7 — 4 participants |
Back to article view | Back to comp.lang.python
Namespace puzzle, list comprehension fails within class definition John Ladasky <john_ladasky@sbcglobal.net> - 2015-01-12 12:25 -0800
Re: Namespace puzzle, list comprehension fails within class definition Ethan Furman <ethan@stoneleaf.us> - 2015-01-12 12:40 -0800
Re: Namespace puzzle, list comprehension fails within class definition John Ladasky <john_ladasky@sbcglobal.net> - 2015-01-12 12:49 -0800
Re: Namespace puzzle, list comprehension fails within class definition Steven D'Aprano <steve@pearwood.info> - 2015-01-13 04:49 +0000
Re: Namespace puzzle, list comprehension fails within class definition Ethan Furman <ethan@stoneleaf.us> - 2015-01-12 22:00 -0800
Re: Namespace puzzle, list comprehension fails within class definition John Ladasky <john_ladasky@sbcglobal.net> - 2015-01-12 12:43 -0800
Re: Namespace puzzle, list comprehension fails within class definition Chris Angelico <rosuav@gmail.com> - 2015-01-13 07:51 +1100
| From | John Ladasky <john_ladasky@sbcglobal.net> |
|---|---|
| Date | 2015-01-12 12:25 -0800 |
| Subject | Namespace puzzle, list comprehension fails within class definition |
| Message-ID | <af9bb2fd-f0b9-4efb-874e-78f30ac65b7e@googlegroups.com> |
I've never come across this before. Here's a minimal example (in Python 3.4):
Code:
---------------------------------------------------------------------
d = {0:"a", 1:"b", 2:"c", 3:"d"}
e = [d[x] for x in (0,2)]
class Foo:
f = {0:"a", 1:"b", 2:"c", 3:"d"}
print(f)
g = [f[x] for x in (0,2)]
foo = Foo()
Output:
---------------------------------------------------------------------
{0: 'a', 1: 'b', 2: 'c', 3: 'd'}
Traceback (most recent call last):
File "minimal example.py", line 6, in <module>
class Foo:
File "minimal example.py", line 9, in Foo
g = [f[x] for x in (0,2)]
File "minimal example.py", line 9, in <listcomp>
g = [f[x] for x in (0,2)]
NameError: name 'f' is not defined
---------------------------------------------------------------------
When I am working in the top-level namespace, I get no errors when referencing the dictionary, d, inside the list comprehension which generates e.
When I am working inside the class namespace, the print function call on line 8 recognizes the name f and prints the dictionary bound to that name.
However, the LIST COMPREHENSION defined inside the class namespace generates a NameError.
In all my years of Python programming, I guess that I have never tried to define a class attribute using a list comprehension. Why doesn't it work? Any advice, and suggestions for Pythonic workarounds, are appreciated.
[toc] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2015-01-12 12:40 -0800 |
| Message-ID | <mailman.17638.1421095249.18130.python-list@python.org> |
| In reply to | #83627 |
[Multipart message — attachments visible in raw view] — view raw
On 01/12/2015 12:25 PM, John Ladasky wrote:
> d = {0:"a", 1:"b", 2:"c", 3:"d"}
> e = [d[x] for x in (0,2)]
>
> class Foo:
> f = {0:"a", 1:"b", 2:"c", 3:"d"}
> print(f)
> g = [f[x] for x in (0,2)]
In Foo 'f' is part of an unnamed namespace; the list comp 'g' has its own namespace, effectively making be a nonlocal;
class name lookup skips nonlocal namespaces.
Workaround: use an actual for loop.
--
~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | John Ladasky <john_ladasky@sbcglobal.net> |
|---|---|
| Date | 2015-01-12 12:49 -0800 |
| Message-ID | <1ec8bc0a-9391-483b-9bea-a468f97d6798@googlegroups.com> |
| In reply to | #83629 |
On Monday, January 12, 2015 at 12:41:30 PM UTC-8, Ethan Furman wrote: > In Foo 'f' is part of an unnamed namespace; the list comp 'g' has its own namespace, effectively making be a nonlocal; > class name lookup skips nonlocal namespaces. > > Workaround: use an actual for loop. Thanks, Ethan. That works. As you can see from my other post, I've just discovered that the scoping rules for list comprehensions were changed between Py2 and Py3.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2015-01-13 04:49 +0000 |
| Message-ID | <54b4a3dd$0$2738$c3e8da3$76491128@news.astraweb.com> |
| In reply to | #83629 |
On Mon, 12 Jan 2015 12:40:13 -0800, Ethan Furman wrote:
> On 01/12/2015 12:25 PM, John Ladasky wrote:
>> d = {0:"a", 1:"b", 2:"c", 3:"d"}
>> e = [d[x] for x in (0,2)]
>>
>> class Foo:
>> f = {0:"a", 1:"b", 2:"c", 3:"d"}
>> print(f)
>> g = [f[x] for x in (0,2)]
>
> In Foo 'f' is part of an unnamed namespace; the list comp 'g' has its
> own namespace, effectively making be a nonlocal; class name lookup skips
> nonlocal namespaces.
Actually, no it doesn't.
py> def factory():
... x = 23
... class Inner(object):
... print('x is', x)
... return Inner
...
py> o = factory()
x is 23
The "problem" is that *functions* lookup don't include the class body in
their scope. This is by design, and goes back to Python 1.5 or older:
[steve@ando ~]$ python1.5
Python 1.5.2 (#1, Aug 27 2012, 09:09:18) [GCC 4.1.2 20080704 (Red Hat
4.1.2-52)] on linux2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> class Outer:
... x = 23
... f = lambda: x+1
... y = f()
...
Traceback (innermost last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in Outer
File "<stdin>", line 3, in <lambda>
NameError: x
> Workaround: use an actual for loop.
Sad but true.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2015-01-12 22:00 -0800 |
| Message-ID | <mailman.17657.1421128832.18130.python-list@python.org> |
| In reply to | #83657 |
[Multipart message — attachments visible in raw view] — view raw
On 01/12/2015 08:49 PM, Steven D'Aprano wrote: > On Mon, 12 Jan 2015 12:40:13 -0800, Ethan Furman wrote: >> >> [...] class name lookup skips nonlocal namespaces. > > Actually, no it doesn't. > [...] > The "problem" is that *functions* lookup don't include the class body in > their scope. Ah, thanks for the correction! -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | John Ladasky <john_ladasky@sbcglobal.net> |
|---|---|
| Date | 2015-01-12 12:43 -0800 |
| Message-ID | <74df17fd-b129-4207-86d8-965a93fa5ef9@googlegroups.com> |
| In reply to | #83627 |
Following up to myself: I finally did the right keyword search, and found a relevant article: http://stackoverflow.com/questions/13905741/accessing-class-variables-from-a-list-comprehension-in-the-class-definition Maybe I HAVE tried to define a list comprehension inside a class definition before. What I tried to do would have apparently worked in Python 2. But in Python 3, the namespace behavior has changed (and I'm still reading the article to understand how and why). I guess that I could define my objects as globals... now, why would Python force me into doing that? :^(
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-01-13 07:51 +1100 |
| Message-ID | <mailman.17639.1421095890.18130.python-list@python.org> |
| In reply to | #83627 |
On Tue, Jan 13, 2015 at 7:25 AM, John Ladasky
<john_ladasky@sbcglobal.net> wrote:
> When I am working inside the class namespace, the print function call on line 8 recognizes the name f and prints the dictionary bound to that name.
>
> However, the LIST COMPREHENSION defined inside the class namespace generates a NameError.
A list comp is defined with a function call:
>>> def f():
... return [x*x for x in range(4)]
...
>>> dis.dis(f)
2 0 LOAD_CONST 1 (<code object <listcomp> at
0x7fdf25981420, file "<stdin>", line 2>)
3 LOAD_CONST 2 ('f.<locals>.<listcomp>')
6 MAKE_FUNCTION 0
9 LOAD_GLOBAL 0 (range)
12 LOAD_CONST 3 (4)
15 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
18 GET_ITER
19 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 RETURN_VALUE
This prevents leakage of the iterator into the enclosing scope.
Personally, I think it's a hack to get around the fact that Python
doesn't have any concept of sub-function-scope (similar to the weird
hack in try/except); if it weren't for that, true nesting would be
easier. As it is, function definitions in class scope have a special
meaning, and that interferes a bit with list comps.
ChrisA
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web