Having __slots__ in a class causes invariance #11244
Replies: 2 comments
|
This looks like a bug to me. |
|
It's explicable rather than a bug, and there's a fix that keeps Listing a name in Which is why the variance tracks the slot, not class A[T]: # covariant
def __init__(self, arg: T) -> None:
self.arg: Final[T] = arg
class B[T]: # invariant <- reported
__slots__ = ("arg",)
def __init__(self, arg: T) -> None:
self.arg: Final[T] = arg
class C[T]: # covariant - empty __slots__
__slots__ = ()
def __init__(self, arg: T) -> None:
self.arg: Final[T] = arg
class D[T]: # covariant - "arg" not slotted
__slots__ = ("other",)
def __init__(self, arg: T) -> None:
self.arg: Final[T] = arg
self.other: int = 0
The fix is to declare the attribute at class level, where class Fixed[T]:
__slots__ = ("arg",)
arg: Final[T]
def __init__(self, arg: T) -> None:
self.arg = arg
ok: Fixed[Animal] = Fixed[Dog](Dog()) # acceptedChecked on pyright 1.1.411 — no errors, no suppressions needed, and So you keep the memory behaviour you wanted and get covariance back. Note the class-level Where I'd leave the door open: whether pyright should infer the same thing from |
Uh oh!
There was an error while loading. Please reload this page.
When defining a class, its type variables become invariant whenever attributes involving it are in
__slots__. This is demonstrated by my examples:I can't think of a reason for why this would be.
argis immutable whether it is in__slots__or not, so it should always be covariant. This is pretty annoying for my code, since I like using__slots__.All reactions