[EN] Static type checking in Python
from typing import ClassVar class People(object): name: ClassVar[str] = "???" def __init__(self): pass def main() -> None: p1 = People() p2 = People() print("p1 = ", p1.name) # referencing class variable (People.name) print("p2 = ", p2.name) # referencing class variable (People.name) p1.name = "homer" print("p1 = ", p1.name) # referencing instance variable (overrides the class variable) print("p2 = ", p2.name) # referencing class variable People.name = "!!!" print("p1 = ", p1.name) # referencing instance variable print("p2 = ", p2.name) # referencing class variable # python id() guarantees the returned value is unique and constant for the object during its lifetime. print(id(People.name)) print(id(p1.name)) print(id(p2.name)) if __name__ == "__main__": main()
(Execution Result) p1 = ??? p2 = ??? p1 = homer p2 = ??? p1 = homer p2 = !!! 139748878051456 139748878013920 # id(People.name) != id(p1.name) 139748878051456 # id(People.name) = id(p2.name)
In Python, variables defined outside
__init__ function are considered class variables, which are shared by all instances of the class.
In the above example, the statement
p1.name = "homer" shadows the class variable with the instance variable.
The syntax of accessing a class variable via instance is accepted, but this flexibility makes us confused and Python’s dynamic type checking will not complain about this.
Combined with Python 3.6’s type hints, there is a great static type checking tool called mypy.
$ mypy <python source> class-instance-variable.py:16: error: Cannot assign to class variable "name" via instance
The tool generates an error because I explicitly mentioned the “name” should be a class variable, not an instance variable.