2

I want to have attribute that is shared by and accessible to all instances of a class.

Sample code:

class Test:

    code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
    code2d = [ [ code[j*3 + i] for i in range(3) ] for j in range(3) ]

    def __init__(self):
        pass

However, I get error:

NameError: name 'code' is not defined

If I put the lines with code and code2d into init method, all is working properly.

Why this code throws the error?

WispyCloud
  • 4,140
  • 1
  • 28
  • 31
hakubaa
  • 169
  • 1
  • 4
  • 14

1 Answers1

3

code is a class variable , and hence when accessing it you need to call - Test.code , you cannot access them using code .

Also, even if you do access them using Test.code , it would still not work, because the value for class variables (default value) is calculated when the class is being defined, so when you try to access Test.code , you would not be able to access Test as it has not been created yet. Example of that -

>>> class Test:
...     code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
...     code2d = [ [ Test.code[j*3 + i] for i in range(3) ] for j in range(3) ]
...     def __init__(self):
...         pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in Test
  File "<stdin>", line 3, in <listcomp>
  File "<stdin>", line 3, in <listcomp>
NameError: name 'Test' is not defined

I am guessing when you put them in the __init__() you are putting them as -

class Test:

def __init__(self):
    code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
    code2d = [ [ code[j*3 + i] for i in range(3) ] for j in range(3) ]

This would work, because code here is a local variable and hence can be accesed by the other local variables in the __init__() method , though they would not be accessible outside this function.


Maybe, you do not need them as class variables , if you want to have code and code2d for all instances of the class (objects of the class) , you should create instance variable as-

>>> class Test:
...     def __init__(self):
...         self.code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
...         self.code2d = [ [ self.code[j*3 + i] for i in range(3) ] for j in range(3) ]

If you really want code and code2d to be class variables , one way to do it would be to define code2d outside the class Test , example -

class Test:
    code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
    def __init__(self):
        pass


Test.code2d = [ [ Test.code[j*3 + i] for i in range(3) ] for j in range(3) ]
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • *If I put the lines with 'code' and 'code2d' into init method, all is working properly. I don't understand why this code throws the error.* You are not explaining why it doesn't work when trying to use this in the class body; the OP *already knows* it works when you put this in the `__init__` method. – Martijn Pieters Jul 19 '15 at 08:20
  • @MartijnPieters Added that based on a guess, though he didn't put the code for which it was working, so I didn't put that case. – Anand S Kumar Jul 19 '15 at 08:23
  • @MartijnPieters I said in the start - `code is a class variable , and hence when accessing it you need to call - Test.code , you cannot access them using code .` , this explains it. – Anand S Kumar Jul 19 '15 at 08:24
  • So why doesn't it work when using that exact code when creating *class attributes*? Hint: see the duplicate. – Martijn Pieters Jul 19 '15 at 08:24
  • Ok, thanks for help. I guess I will define code2d outside the class. – hakubaa Jul 19 '15 at 08:28