Search code examples
pythonpycharmpython-typing

Python class members type hinting


I am using PyCharm to develop some Python app. I am trying to use as cutting-edge python as possible, so I am making use of new python features. I have a problem with type hinting.

Let's all take a look at my DataAnalyzer class:

class DataAnalyzer:

    def __init__(self, train_data: pd.DataFrame, test_data: pd.DataFrame) -> None:
        self.train_data = train_data
        self.test_data = test_data

    def analyze(self):
        pass

Now PyCharm spams me with yellow bulbs wanting me to add type annotations to self.train_data and self.test_data. If I click this message to do so, PyCharm adds two lines at the beginning of my class:

class DataAnalyzer:
    train_data: pd.DataFrame
    test_data: pd.DataFrame

    def __init__(self, train_data: pd.DataFrame, test_data: pd.DataFrame) -> None:
        self.train_data = train_data
        self.test_data = test_data

    def analyze(self):
        pass

I guess now it looks nicer, but AFAIK by writing those variables like this I make them static.

I thought about annotating the types like this:

class DataAnalyzer:

    def __init__(self, train_data: pd.DataFrame, test_data: pd.DataFrame) -> None:
        self.train_data: pd.DataFrame = train_data
        self.test_data: pd.DataFrame = test_data

    def analyze(self):
        pass

Which is definitely not clear, but I am not making my class members static, when I don't want to.

I know, that by having the types annotated in the method signature, doing this one more time when I just assign those, is an overkill, but I am asking for the general rule. Should I annotate those types like PyCharm suggests me to, or should I do this inline?


Solution

  • PyCharm's suggest is right. In fact, I think the following code is better:

    class DataAnalyzer:
        train_data: pd.DataFrame
        test_data: pd.DataFrame
    
        def __init__(self, train_data, test_data):
            self.train_data = train_data
            self.test_data = test_data
    
        def analyze(self):
            pass
    

    Explain:

    • Annotate a member does not make it static.
    • We should not annotate arguments in the __init__ function again.
    • -> None after __init__ can be omitted. For __init__ never return a value.