0

With this sample...

#!/usr/bin/python
class MyClass(object):
    y = 1
    pdq = y
    q = 'abc{}'.format(y)
    z = [_.format(y) for _ in ['a: {}',
                               'b: {}',
                               'c: {}']
         ]
    def __init__(self, val):
        self.val = val

In python2 and python3, MyClass('x').q gets set properly.

In python2.7, MyClass('x').z gets populated properly. It crashes on import in python3, unable to find y inside the comprehension. I'm kind of lost as to why - is Python3 just more aggressive unrolling the comprehension during compile?

Python2

> ipython2
Python 2.7.17 (default, Nov  7 2019, 10:07:09)
In [1]: from tester import MyClass

In [2]: MyClass(123)
Out[2]: <tester.MyClass at 0x7f6a7cb79b90>

In [3]: MyClass(123).val
Out[3]: 123

In [4]: MyClass(123).z
Out[4]: ['a: 2', 'b: 2', 'c: 2']

Python3

> ipython3
Python 3.7.5 (default, Nov  7 2019, 10:50:52)

In [1]: from tester import MyClass
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-718df2f3bae2> in <module>()
----> 1 from tester import MyClass

tester.py in <module>()
      1 #!/usr/bin/python3
----> 2 class MyClass(object):
      3     x = 1
      4     y = 2
      5     pdq = y

tester.py in MyClass()
      5     pdq = y
      6     q = 'abc{}'.format(y)
----> 7     z = [_.format(y) for _ in ['a: {}',
      8                                'b: {}',
      9                                'c: {}']

tester.py in <listcomp>(.0)
      5     pdq = y
      6     q = 'abc{}'.format(y)
----> 7     z = [_.format(y) for _ in ['a: {}',
      8                                'b: {}',
      9                                'c: {}']

NameError: name 'y' is not defined
martineau
  • 119,623
  • 25
  • 170
  • 301
wom
  • 436
  • 5
  • 16
  • You probably have a global variable `y` defined elsewhere in the first example. Your code fails in both cases. – DYZ Aug 25 '20 at 20:22
  • 1
    Essentially, because in Python 3 a list comprehension creates a function scope. And as is normal, classes do not create an enclosing scope, this is why you have to use `self.some_other_method` inside a method to reference another method. – juanpa.arrivillaga Aug 25 '20 at 21:09
  • @juanpa.arrivillaga That matches the behavior I'm seeing. Is there a trick I could use inside the comprehension to reach out of to the parent scope? – wom Aug 26 '20 at 04:18
  • Edit* Linked similar question from 7 years back answers my question exactly. Leaving question up incase others can find it if they can't find the original like I didn't. – wom Aug 26 '20 at 04:52
  • 1
    @wom no, nothing sane. Just dont' use a list comprehension. Or alternatively, use it outside the class definition. I'd I'd just use a regular loop. – juanpa.arrivillaga Aug 26 '20 at 08:04

0 Answers0