Learn more about the latest StingrayReader upgrade!
Join the DZone community and get the full member experience.Join For Free
Before getting started, check out this GitHub repo with all the code you need for this demonstration.
So, without further ado, it's time to add type hints and learn some interesting lessons from it.
You may also like: The SourceForge Vs. GitHub Conundrum
Here's the problem:
While valid, this concerns mypy.
The point here is to have a flexible source of data, source. Perhaps this is a spreadsheet row, or a complex JSON/YAML-formatted document with optional or irrelevant fields. The short list of relevant names is in
the_names. Ideally, this list of names matches the keyword args of
This gives mypy fits because there's no way to match the dictionary with the object's parameters.
We have two paths forward.
- Eliminate the intermediate dictionary. Use
SomeClass(x=source['x'], y=source['y'], ... etc.)
- Consider using a
TypedDictfor the intermediate dictionary. But then, the dictionary's types must be kept in sync with the
SomeClassdefinition, which may be a little crazy.
SomeClassdefinition has a **kwargs option, allowing extra attributes to be set. This is, perhaps also crazy. But, the framework needs to drag around extra attributes for the application's benefit.
A possibility is to do away with **kwargs, and replace it with other:
Dict[Any, Any]. This cuts down on the expressivity of the framework. Now, we support
SomeClass.app_name. This change would mean we'd have
SomeClass.other['app_name']. While possibly better for mypy, I don't think it's ideal for users.
I can also rework
SomeClass to use
__getattribute__() to look into self.other for extra attribute names.
I'm very happy to have a rigorous static check. The rethinking is helpful.
("Wait," you say. "You didn't provide the recommended path forward." Correct. I'll update.)
Published at DZone with permission of Steven Lott, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.