2

I'm trying to understand the following Python code

class MyClass():
    aa:int
    

What is happening here? It seems to me that the variable aa is a class variable which is declared but not initialized. The :int seems to be a typing hint. Am I correct? I can instantiate the class but I cannot access aa. Which makes me think that my understanding is wrong. See below

 mm = MyClass()
 mm.aa
Traceback (most recent call last):

  File "<ipython-input-15-cfce603dd5e0>", line 1, in <module>
    mm.aa

AttributeError: 'MyClass' object has no attribute 'aa'
Georgy
  • 12,464
  • 7
  • 65
  • 73
NNN
  • 697
  • 1
  • 5
  • 15

1 Answers1

3

Indeed, this only creates an annotation for the attribute, it does not create the attribute itself. Attributes and variables are only created by assignment, and nothing's being assigned here, so it doesn't exist (not even with an implicit None or such).

This pattern is useful to satisfy type checkers if the attribute is initialised outside of __init__, e.g.:

class MyClass(SomeParentClass):
    aa: int

    def initialize(self):
        self.aa = 'foo'

Let's say that SomeParentClass will call initialize at some defined point during its instantiation process and it wants subclasses to use initialize to do their initialisations, instead of overriding __init__. A type checker might complain here that aa is created outside of __init__ and is therefore not safe to access. The aa: int annotation explicitly says that aa should be expected to exist as an int at any time, so is safe to access (taking care that that'll actually be the case is your responsibility then). An example of this kind of pattern can be found in Tornado, for instance.

Another use of these annotations of course are classes where those annotations are explicitly used at runtime, like Python's own dataclasses do.

deceze
  • 510,633
  • 85
  • 743
  • 889