1

I want to create a static variable in python for a class and instantiate it with the same type i.e.

class TestVarClass():
    # this is my static variable here
    testVar = None

    def __init__(self, value):
        # instance variable here
        instanceVar = 0

# instantiating the static variable with its own type
TestVarClass.testVar = TestVarClass(1)

Since python is an interpreting language, I cannot instantiate the static object inside the class before init. Hence, I placed it outside the class. But when I debug this in pycharm, the variable testVar comes with infinite nesting like below:

enter image description here

  1. What does this mean? Since the address at every level is same - it doesn't look like it is allocating multiple times but hen why does the debugger show the value like this?
  2. I basically want to achieve creating a static and read-only variable in python and ended up here.
user3004790
  • 748
  • 7
  • 10
  • 1
    I don't know why the debugger shows that, but here's a helpful comment on static/read-only variables in python: https://stackoverflow.com/questions/68645/are-static-class-variables-possible-in-python/27568860#27568860 – Marcus Weinberger Aug 05 '19 at 19:10
  • The approach mentioned on the link you gave will work fine if the static variable can be instantiated for any type other than the class type – user3004790 Aug 05 '19 at 19:25
  • 1
    *"What does this mean?"* You have created an instance of `TestVarClass` and assigned it to `testVar` class attribute (of said class), which is accessible from that class and each of its instances (but is still the same class attribute and refers to the same object). – Ondrej K. Aug 05 '19 at 19:25
  • @ondrej, yes but why so levels in the screenshot? I created only one instance, so it shouldn't show the nesting these many times? – user3004790 Aug 05 '19 at 19:28

1 Answers1

0

Why do you see what you see? You have created an instance of TestVarClass and assigned it to testVar class attribute, which is accessible from that class and each of its instances (but is still the same class attribute and refers to the same object). It would be the same as a simplified example of:

>>> class C:
...     pass
... 
>>> C.a = C()
>>> C.a
<__main__.C instance at 0x7f14d6b936c8>
>>> C.a.a
<__main__.C instance at 0x7f14d6b936c8>

class C now having attribute a itself being instance of C. I can access C.a and since that is instance of C and I can access its C.a (or C.a.a). And so on. It's still the very same object though.

Python doesn't really have static variables. Well, it sort of does, but as a side effect of default argument values being assigned once when a function is being defined. Combine that with behavior (and in-place modification) of mutable objects. And you essentially get the same behavior you'd expect form a static variable in other languages. Take the following example:

>>> def f(a=[]):
...     a.append('x')
...     return id(a), a
... 
>>> f()
(139727478487952, ['x'])
>>> f()
(139727478487952, ['x', 'x'])
>>> 

I am not entirely sure what exactly are you after. Once assigned, class attribute lives with the class and hence could be considered static in that respect. So I presume assign only once behavior interests you? Or to expose the class attribute in instances without being able to assign to it instances themselves? Such as:

>>> class C:
...     _a = None
...     @property
...     def a(self):
...         return self._a
... 
>>> C._a = C()
>>> c = C()
>>> print(c.a)
<__main__.C object at 0x7f454bccda10>
>>> c.a = 'new'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Or if you wanted to still use a in both class and instance?

>>> class C:
...     a = None
...     def __setattr__(self, name, value):
...         if name == 'a':
...             raise TypeError("Instance cannot assign to 'a'")
...         super().__setattr__(name, value)
... 
>>> C.a = C()
>>> c = C()
>>> c.a
<__main__.C object at 0x7f454bccdc10>
>>> C.a
<__main__.C object at 0x7f454bccdc10>
>>> c.a = 'new_val'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __setattr__
TypeError: Instance cannot assign to 'a'

Essentially read-only variable (static or not) already sounds a bit like a contradictio in adiecto (not really as much of a variable), but (long story short) I guess the question really is, what is it that you're trying to do (problem you're trying to solve) in a context... and perhaps based on that we could try to come up with a reasonable way to express the idea in Python, but as given without further qualification, Python does not have anything it'd call static read-only variables.

Ondrej K.
  • 8,841
  • 11
  • 24
  • 39
  • Thanks Ondrej for the answer. I was trying to convert some C# code to python and faced the need for creating a variable which can behave as static and which is read only. If there isn't a way to achieve that in Python, the way I created testVar in my code can work to let the variable behave in a static manner. – user3004790 Aug 06 '19 at 05:45
  • As mentioned, the same construct is not used in Python (and even an idea of write protected class attribute would be non-trivial to implement) and 1:1 transposition of code is not really an option (or not a practical one), but the question in the end is what behavior really matters to each use case and (how) can I express that in the language I am using. – Ondrej K. Aug 07 '19 at 06:27