joel
joel

Reputation: 7867

Scala's sealed in python

How might I get the benefits of scala's sealed class in python? That is, to make it possible to subclass a class only in the module in which it's defined.

Note not a dupe of this post. C# sealed is equivalent to scala's final.

An example of where I might want this is to define an array type, and specify in that type what its shape is as follows

from typing import final, TypeVar, Generic
from abc import ABC, abstractmethod

S = TypeVar('S', bound=Shape)


class Array(ABC, Generic[S]):
    @abstractmethod
    def shape(self) -> S:
        pass


class Shape(ABC):  # how to make this sealed, or similar?
    pass


@final
class Shape1(Shape):
    pass


@final
class Shape2(Shape):
    pass


def fn(arr: Array[Shape2]):
    # some calculation that requires it to be a rank-2 array

As it is, someone can inherit from Shape and make their own rank 2 shape, which wouldn't be accepted by fn, even though it's valid (sure it's not necessarily a good idea to do that, but users can do what they like).

Other examples are making proper enums. I know there isn't pattern matching, but I imagine it would be confusing to define an Either type and for someone to make a third subclass.

Upvotes: 2

Views: 497

Answers (1)

Feuermurmel
Feuermurmel

Reputation: 9922

I'm assuming that you want to define a type that only allows for Shape1 or Shape2. This is usually done with a type union of the classes defined by the module:

from typing import TypeVar, Generic, TypeAlias

# Only necessary if there is some implementation that should be inherited by 
# Shape1 and Shape2.
class _ShapeBase:
    pass

class Shape1(_ShapeBase):
    pass

class Shape2(_ShapeBase):
    pass

Shape: TypeAlias = Shape1 | Shape2

S = TypeVar('S', bound=Shape)

class Array(Generic[S]):
    def shape(self) -> S:
        raise NotImplementedError

Depending on your implementation, the base class _ShapeBase is redundant and can be removed. If none of the subclasses is shared by the classes, having a common base class is redundant.

Upvotes: 0

Related Questions