Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove error from mypy for attributes set dynamically in a Python class

Tags:

python

mypy

I am using mypy to check my Python code.

I have a class where I set dynamically some attributes and mypy keep on complaining about it:

error:"Toto" has no attribute "age"

This is my code:

class Toto:
    def __init__(self, name:str) -> None:
        self.name = name
        for attr in ['age', 'height']:
            setattr(self, attr, 0)


toto = Toto("Toto")
toto.age = 10  # "Toto" has no attribute "age" :(

Obviously, there could be 3 ways to solve the issue

  1. Ignoring the issue with # type: ignore: toto.age = 10 # type: ignore #...
  2. Using setattr to set the age of toto: setattr(toto, "age", 10)
  3. Setting the attributes explicitly (self.age = 0 ...)

However, I am looking for a more elegant and systematic way at the class level.

Any suggestion?

like image 534
Jean-Francois T. Avatar asked Jun 16 '18 16:06

Jean-Francois T.


People also ask

How do I skip MYPY error?

Silencing errors based on error codes You can use a special comment # type: ignore[code, ...] to only ignore errors with a specific error code (or codes) on a particular line. This can be used even if you have not configured mypy to show error codes.

What is dynamic attribute in Python?

What are dynamic attributes in Python? Dynamic Attributes are the attributes that are declared at runtime or after an object or an instance is created. These only belong to that object or instance only. Thus dynamic attributes are introduced to improve attributes' dynamicity and their security.

What is MYPY used for?

“Mypy is an optional static type checker for Python that aims to combine the benefits of dynamic (or 'duck') typing and static typing. Mypy combines the expressive power and convenience of Python with a powerful type system and compile-time type checking.” A little background on the Mypy project.


1 Answers

I don't follow mypy well enough to know whether this is (still, or ever was) the ideal work around, but this issue and this part of the cheatsheet indicate that something like:

from typing import Any

class Toto:
    def __init__(self, name:str) -> None:
        self.name = name
        for attr in ['age', 'height']:
            setattr(self, attr, 0)

    def __setattr__(self, name:str, value:Any):
        super().__setattr__(name, value)

toto = Toto("Toto")
toto.age = 10

Will allow you to do what you're doing without mypy complaining (which it does, just tested).

Any could be more restrictive, but the types will be checked on both setattr() and "traditional" obj.attr = ... calls, so heads up.

like image 65
jedwards Avatar answered Oct 14 '22 05:10

jedwards