Reputation: 7867
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
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