1

I need a way to create a static class variable in Python that only the class will have. I can't afford this variable to be created over and over again for each instance, because the target class variable will be a huge read-only data structure. Each instance must be able to access it for read-only purposes throught the class, but since it's a giant bulk of data and there will be thousands instances, I can't afford that each instance will create another copy of this data structure again.

I found this question, but it doesn't solve my problem, because the static class variable suggested is created for each instance:

>>> class MyClass():
    i = 1
>>> m = MyClass()
>>> m.i
1

In other words, I'm looking for a static class variable like in PHP:

<?php
class Foo
{
    public static $my_static = 'foo';
}

$foo = new Foo();
print $foo::$my_static . "\n";     // Accessable throught the class
print $foo->my_static . "\n";      // Undefined "Property" my_static     
?>

This is exactly what I need, the static class variable is created only once for the class, all instances can access it throught the class but this static class variable isn't created over and over for each new instance. Is it possible to create a static class variable like this in Python?

PS: I now there are some workarounds if I don't use OOP, but if I could find a good and clearly readable OOP solution it would make more sense in the project as a whole.

Community
  • 1
  • 1
renatov
  • 5,005
  • 6
  • 31
  • 38
  • 3
    Why do you think that just because you can _access_ it as `m.i` it's actually getting _created_ multiple times? – tzaman May 12 '15 at 22:15
  • *"the static class variable suggested is created for each instance"* - no, that's not correct. – jonrsharpe May 12 '15 at 22:15
  • That you can acces it from an instance does not mean it is created for each instance. – Mike Müller May 12 '15 at 22:15
  • @tzaman isn't it? If I assign a new value for `m.i` it will be different from `MyClass.i` – renatov May 12 '15 at 22:16
  • @renatov why would you assign a new value to the instance? – jonrsharpe May 12 '15 at 22:17
  • 1
    @renatov **if** you assign `m.i` on an instance, at that point it creates a new one, shadowing the class var. – tzaman May 12 '15 at 22:17
  • @tzaman hmmm I didn't know Python worked like this. So `m.i` and `MyClass.i` are the same if I just access them as read-only? – renatov May 12 '15 at 22:19
  • 1
    @renatov yup, exactly. – tzaman May 12 '15 at 22:19
  • @tzaman thank you very much for your help! I'm still learning Python and the OOP part is very unclear to me yet. I read the documentation, but a lot of things were left apart, unfortunately. Thanks again! – renatov May 12 '15 at 22:23
  • @tzaman where exactly did you learn all these things about Python OOP? The material I've read so far have never mentioned something like that. Did you study Python OOP by a particular book or tutorial? – renatov May 12 '15 at 23:29
  • @renatov no specific books; the main Python tutorial and the page about the data model are instructive though. – tzaman May 13 '15 at 23:00

2 Answers2

4

the static class variable suggested is created for each instance

That is false, as you can easily demonstrate:

>>> class Test():
    class_attr = []


>>> t1 = Test()
>>> t2 = Test()
>>> t1.class_attr is t2.class_attr
True  # this means that they reference exactly the same object
>>> t1.class_attr.append(1)  # alter via t1
>>> t2.class_attr
[1]  # see the changes via t2

However, you can override the class attribute with an instance attribute:

>>> t1.class_attr = []
>>> t1.class_attr is t2.class_attr
False

so if you need to replace the class attribute (rather than alter it in-place, as the append did) you should do so via the class, not the instance (in this case, Test.class_attr = [] would have affected both t1 and t2).

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • where did you learn Python OOP? All the documentation I've read has never mentioned anything like what you pointed out. Did you read some particular book or tutorial? – renatov May 12 '15 at 23:30
  • @renatov I can't answer specifically, but note that this is covered in e.g. the official Python tutorial: https://docs.python.org/2/tutorial/classes.html#class-and-instance-variables – jonrsharpe May 13 '15 at 06:34
1
class MyClass():
    i = 1

inst = MyClass()

All attributes of a class are stored in __dict__. It contains i (in addition to a bunch of other things):

>>> MyClass.__dict__
mappingproxy({'__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'__module__': '__main__', '__dict__': <attribute '__dict__' of 'MyClass'
 objects>, 'i': 1, '__doc__': None})

The instance does not have any attributes:

>>> inst.__dict__
{}

If i cannot be found in inst.__dict__ the search continues in MyClass.__dict__. Even though it looks a bit like the instance has an attribute i, it actually exist in the class only.

As soon as you assign to the instance:

inst.i = 10

the this changes:

>>> inst.__dict__
{'i': 10}

Now, the instance has its own attribute.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
  • Great answer, thanks! The OOP part in Python is very confusing to me. I'll start using the `__dict__` to check what is created and what is not. – renatov May 12 '15 at 22:26
  • 1
    @renatov note that you can have `__slots__` instead of `__dict__`, and the built-in types don't have either, so this isn't always possible – jonrsharpe May 12 '15 at 22:28