I am using python 3.10, and switched from Dict
to TypedDict
for the annotations. Following the advice of Pep 655, I'm importing from typing_extensions
instead of typing
; I also want NotRequired
, which can only be imported from typing_extensions
at this version.
I've noticed that I can overload __getattr__
(and __getattribute__
) for Dict
, OrderedDict
, and even typing.TypedDict
just fine, but that it is ignored for typing_extensions.TypedDict
children. Why is this, and is there a way around it?
Example:
from typing_extension import TypedDict
from typing import Dict, TypedDict as TypedDict2
class PerfectlyFineDict(Dict):
def __getattr__(self, key): return self[key]
class PerfectlyFineDict2(TypedDict2):
def __getattr__(self, key): return self[key]
f = PerfectlyFineDict(a=1)
print(f['a']) # Of course, prints "1"
print(f.a) # Works perfectly fine - prints "1"
f = PerfectlyFineDict2(a=1)
print(f['a']) # Of course, prints "1"
print(f.a) # Works perfectly fine - prints "1"
class FailingDict(TypedDict):
def __getattr__(self, key): return self[key]
f = FailingDict(a=1)
print(f['a']) # Of course, prints "1"
print(f.a) # AttributeError: 'dict' object has no attribute 'a'
I would rather not import TypedDict
from typing
and NotRequired
from typing_extensions
, since it seems to be against the PEP standard and I'm not sure how it will interact with the lexer (probably fine), but I'm not sure what the alternative is.
As written in PEP 589, under class based syntax
Methods are not allowed, since the runtime type of a TypedDict object will always be just dict (it is never a subclass of dict).
And indeed
f = PerfectlyFineDict2(a=1)
print(type(f))
shows that it is still just a <class 'dict'>
.
You are simply only expected to use it as they describe
class PerfectlyFineDict2(TypedDict2):
stuff: int
things: str
PyCharm was clever enough to detect this attempt and gave a yellow squiggly indicator with a helpful link to the exact explanation.
As far as I understand it, this class based syntax is just borrowing the syntax of inheritance, but it's really just meta-class black magic where anything goes.