Description
Motivation - Python does not have a concept or notion of object const-ness. The const-ness is normally conveyed via doc strings which explain the usage contracts of the frameworks involved. However, this does not provide the necessary formalism required for static analysis tools (like pytype) to flag const-ness contract violations. Hence, we propose to add const-ness type hints to PEP-484 which can be used by static analysis tools to flag const-ness contract violations.
The Proposal
We propose adding two constructs:
The @constmethod
decorator
This decorator can only be used to decorate instance methods. It describes methods which do not modify the instances on which they are invoked. That is, a method decorated with this decorator a) should not modify the fields on the object, b) should not call other methods which modify the fields of the object, c) and it should not pass non-primitive fields of the object to other callables which modify them.
Normally, this decorator would be used on getters. For example:
from typing import constmethod
class MyClass(object):
...
@constmethod
def get_something(self) -> int: ...
The protocol type-hint Const
This type-hint is used to describe function arguments and return values. When used to describe a function argument, it indicates that the function argument will not be modified by the function. It should only be used for non-primitive types. Example:
from typing import Const
def my_function(alist: Const[List[SomeClass]]) -> int: ...
The above indicates that the list argument alist will not be modified by my_function. Note that it does not indicate that the elements of the list are also not modified. If it is desired to indicate that even the elements are not modified, then one should use:
def my_function(alist: Const[List[Const[SomeClass]]]) -> int: ...
When Const
is used as a type-hint on return values, it indicates that the value returned should not be modified by the caller. Example:
def my_function() -> Const[List[SomeClass]]: ...
This indicates that the returned list object should not be modified by the caller. As before, it does not indicate that the elements of the returned list should also not be modified. If even element const-ness is desired, then one should use:
def my_function() -> Const[List[Const[SomeClass]]]: ...