5

I am a bit puzzled why when initializing an instance of a class in Python, I cannot use class attributes. Here is the example:

class TestClass:
... shared_list = ['a', 'b', 'c']
... def __init__(self):
...     self.length = len(shared_list)

Now

>>> TestClass.shared_list
['a', 'b', 'c']

So the list exists before any instance of the class appears, but

>>> tc = TestClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __init__
NameError: global name 'shared_list' is not defined

Am I missing something simple?

UPD: Thanks to everyone for help and a prompt response. I've cleared up my confusion: class doesn't define a scope in Python.

LazyCat
  • 496
  • 4
  • 14
  • 7
    You need `self.shared_list` or `TestClass.shared_list` if you want the scoped `shared_list` – AChampion Sep 30 '16 at 14:09
  • @AChampion Thanks, putting TestClass.shared_list fixes it. Coming from C++ I still find it confusing, that *within* the class I need an explicit reference to the class. I thought if an attribute is not found in the instance, it will be searched for in the class, and not globally, no? – LazyCat Sep 30 '16 at 14:16
  • 1
    Unfortunately not, see scoping rules post above. – AChampion Sep 30 '16 at 14:17

3 Answers3

3

A class definition doesn't create a new scope for its methods, just a namespace for local variables. This is documented to some extent in Class Definition Syntax:

When a class definition is entered, a new namespace is created, and used as the local scope — thus, all assignments to local variables go into this new namespace. In particular, function definitions bind the name of the new function here.

When a class definition is left normally (via the end), a class object is created. This is basically a wrapper around the contents of the namespace created by the class definition.

That's why you need to reference the class attribute as TestClass.shared_list or self.shared_list in its method.

Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
2

The problem occurs in your __init__ function, which is called when you instantiate TestClass.

The __init__ function uses the shared_list variable, but in reality this variable can only be used when tied to an instance or the base class itself. If you want to modify the shared variable, you will have to call it with the class name:

def __init__(self):
    self.length = len(TestClass.shared_list)

If you want to modify the variable only for that instance, you will have to declare it as an instance variable:

def __init__(self):
    self.not_shared_list = ['a', 'b', 'c']
    self.length = len(self.not_shared_list)
brianpck
  • 8,084
  • 1
  • 22
  • 33
  • 1
    Note: `self.share_list` will reference the `TestClass.shared_list` and any changes to `self.share_list` will modify the class variable. – AChampion Sep 30 '16 at 14:14
  • @AChampion Thanks--modified accordingly. – brianpck Sep 30 '16 at 14:20
  • Thanks, - I've upvoted your answer, but I accepted a different one, since it happened to address exactly my source of confusion: class doesn't create a scope in Python. – LazyCat Sep 30 '16 at 14:39
1

If you do not specify the "environment" of the variable shared_list, here it's self or TestClass, python thinks it is a global variable - which is nor defined.

Use self.shared_list or TestClass.shared_list to reference it.

Mijago
  • 1,569
  • 15
  • 18