Home > Software design >  Elegant solution in Python for strict objects without duplicating fields in __slots__?
Elegant solution in Python for strict objects without duplicating fields in __slots__?

Time:10-19

We have a bigger Python project and the run-time errors became more and more annoying, like mistypings, that would be avoidable using a compiled language. I started to use the typing feaures of Python to catch many errors in code "inspection" time instead of runtime, like in C or ObjectPascal. Using type annotation and PyCharm is much better, though I have discovered a serious problem:

class TNormalClass():
    def __init__(self):
        self.x : int = 1

c1 = TNormalClass()
c1.x = 2
c1.y = 5  # no error signalized here, but should have been!

After searching on the Internet i've found a solution with __slots__:

class TStrictClass():
    __slots__ = ['x']
    def __init__(self):
        self.x : int = 1

c1 = TStrictClass()
c1.x = 2
c1.y = 5  # PyCharm code inpection warning   runtime error: "object has no attribute 'y'"

That's what I wanted, but e.g. we have an object with 40 long named members. Duplicating every name in the __slots__ is far from elegant in the year 2022.

I've tried the library "autoslot", the c1.y = 5 resulted in runtime error, but this error was not detected inspection time with the PyCharm.

Is there some feature already in Python or maybe planned something in 3.10 which would help me to create my "strict" objects

  • without duplicating every member in the __slots__
  • and also works with the PyCharm code inspection?

br, nvitya

CodePudding user response:

This has been answered here: Prevent creating new attributes outside __init__

As the second answer there says, __slots__ is the pythonic way.

CodePudding user response:

As suggested in the comments, you probably want to try using dataclasses that were introduced in Python 3.7. If you want more features or need to support older versions of Python you could try using the attrs package that dataclasses was based on.

I'd write your code as:

from dataclasses import dataclass

@dataclass(slots=True)
class TNormalClass:
    x: int = 1

Note that slots was only introduced in Python 3.10, hence my references to the attrs package.

These declarations are exposed to Python's typing support, so will be picked by tools like mypy and by editors like PyCharm.

  • Related