Reputation: 104
Suppose we have a class definition:
class A:
z: 1
b: 2
Z: 3
g: 4
C: 5
A: 6
d: 7
The standard CPython gives this value for A.__annotations__
:
{
'z': 1,
'b': 2,
'Z': 3,
'g': 4,
'C': 5,
'A': 6,
'd': 7
}
Is that always the case? What does the specification say about this?
Upvotes: 5
Views: 2060
Reputation: 120678
The specification for the Syntax of Variable Annotations given in PEP 526 states the following:
at the module or class level, if the item being annotated is a simple name, then it and the annotation will be stored in the
__annotations__
attribute of that module or class (mangled if private) as an ordered mapping from names to evaluated annotations.
So an ordered mapping seems to be guaranteed by default. However, the PEP also states the following:
__annotations__
is writable ... But attempting to update__annotations__
to something other than an ordered mapping may result in a TypeError ... (Note that the assignment to__annotations__
... is accepted by the Python interpreter without questioning it - but the subsequent type annotation expects it to be a MutableMapping ...)
So, since a MutableMapping
isn't inherently ordered, it is at least possible that the __annotations__
of a third-party class could be a mapping that defines an arbitrary order:
from collections.abc import MutableMapping
class D(MutableMapping):
def __init__(self, *args):
self._d = {}
def __getitem__(self, key):
return self._d[key]
def __setitem__(self, key, value):
self._d[key] = value
def __delitem__(self, key):
del self._d[key]
def __iter__(self):
return reversed(self._d)
def __len__(self):
return len(self._d)
class A:
__annotations__ = D()
z: 1
b: 2
Z: 3
g: 4
C: 5
A: 6
d: 7
for item in A.__annotations__.items():
print(item)
('d', 7)
('A', 6)
('C', 5)
('g', 4)
('Z', 3)
('b', 2)
('z', 1)
Upvotes: 4