0

I'm quite new to using type hints in python. I have an app with multiple modules in a package and classes associated to them. I've been trying to find some type hint explanation of how it works when there are multiple scripts and the type defined comes from an object whos script is loaded in another module. Here is a very simplified version for this confusion on the use of type hints.

Given that there is a script for the main app like this:

from modules.FigureFormatter import FigureFormatter
from modules.Plotter import Plotter

class MainApp:
    def __init__(self):
        formatter = FigureFormatter()
        plotter = Plotter()
        plotter.plot_figure(formatter.styler['light'])

The modules package contains two modules:

class FigureFormatter:
    def __init__(self):
        self.styler = {'light': {'prop1': 1,
                                 'prop2': 2},
                       'dark': {'prop1': 1,
                                'prop2': 2}}

and

from typing import Dict

class Plotter:
    def __inti__(self):
        # Some initialization stuff
        pass

    def plot_figure(self, styler: Dict):
        # Plotting figure
        pass

What should be the type hint for the styler argument in plot_figure method? Essentially it is a dictionary. Obviously it shouldn't be any dictionary, but a dictionary that is an attribute of the FigureFormatting class instance. Should that module be also imported into Plotter modules, so the class name could be referenced?

1
  • Can you clarify what exactly you want the type hint to express? "a dictionary that is an attribute of the FigureFormatting class instance" is not a type. If you want plot_figure to have access to "a dictionary that is an attribute of the FigureFormatting class instance", why not pass in a formatter: FigureFormatter and access its styler attribute then and there? Commented May 7, 2021 at 14:48

1 Answer 1

1

Python 3.8 introduced a TypedDict hint, which can specify a dictionary with specific str-valued keys mapped to specific types. For example:

# In modules.FigureFormatter
from typing import TypedDict


StylerProperties = TypedDict('StylerProperties', prop1=int, prop2=int)
StylerType = TypedDict('Styler', light=StylerProperties, dark=StylerProperties)

# In modules.Plotter
from modules.Formatter import StylerType


class Plotter:
    ...
    
    def plot_figure(self, styler: StylerType):
        ...

You can also use it TypedDict as a base class, which the documentation suggests is the intended use. (The called version appears to exist to support versions of Python prior 3.6, which don't allow for variable annotations. Note that TypedDict was in the experimental typing_extensions before being promoted to typing.)

class StylerProperties(TypedDict):
    prop1: int
    prop2: int


class Styler(TypedDict):
    light: StylerProperties
    dark: StylerProperties

It doesn't make much sense to further require that the dict comes from a particular class attribute, as being referred to by an attribute doesn't change the dict value. If being an attribute of FigureFormatter is important, then just require an instance of FigureFormatter and extract the dict yourself:

def plot_figure(self, f: FigureFormatter):
    styler = f.styler
    ...
Sign up to request clarification or add additional context in comments.

4 Comments

It seems like this should be in the FigureFormatter module, not the caller, so that the type can be updated when changes are made to the class.
In Python 3.8.5 I'm getting unexpected argument on any argument I'm passing to TypedDict, both by Pycharm 2021.1 and by mypy 0.812 (latest) and the type I pass for these arguments does not seem to have an affect
If it's not obvious, I've never yet used it myself, only knew that it was added to the typing module.:) The documentation suggests that this usage is legal, but you can also use it as a base class, which each key being specified as an annotated class attribute.
I am not sure what the issue with mypy would be (I have very low expectations for PyCharm.) I'm open to making this a community wiki or deferring to someone that can fix this before I can.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.