Closed sylvorg closed 8 months ago
Do you have an example use case? I've only seen Self
used as a return type.
Something like the following:
def __eq__(self: Self, expr: Self) -> bool:
return expr() == self()
So basically, I'd like to be able to check if expr
is an instance of the current class, and I'd like to avoid having to repeat the name of the class if I can help it! 😅 Not to mention I can't seem to use the class name as a type hint anyway...
Would something like types = signature(inspect._findclass(func) if t is Self else t for t in types)
in the __setitem__
method in the multimethod
class work?
There's a lot to consider here. A few thoughts:
Forward references are supported, as a string:
class Base:
def __eq__(self, expr: 'Base') -> bool:
or using a future import:
from __future__ import annotations
...
def __eq__(self, expr: Base) -> bool:
As for Self
, I think there is some ambiguity. Your example looks like the intention is that expr
match the defining class. Whereas it could be more strictly interpreted to match the runtime type of self
. That's analogous to how it works as a return type. Consider:
class Base:
@multimethod
def __eq__(self, expr: Self) -> bool:
return type(self) is type(expr)
class Subclass(Base): ...
assert Base() == Base()
assert Subclass() == Subclass()
assert not Base().eq(Subclass())
assert not Subclass().eq(Base()) # should raise DispatchError? because not isinstance(Base(), Subclass)
3. Python assumes that `__eq__` is commutative, and may reverse the args. Meaning it has an ad-hoc binary dispatch already. So I think this is a particularly confusing example to start with, as opposed to just a normal named method.
self
and expr
, where the class has a custom __call__
method that returns a string that may be the same for both instances.self
could be passed in as the second argument and expr
could be passed in as the first when using __eq__
? So if there was another __eq__
dispatched with expr
annotated as a string, that could get self
instead?Again, sorry for the confusion; while I'm not exactly new to python, I'm not very good with the more complicated aspects of the language! 😅
Would something like
types = signature(inspect._findclass(func) if t is Self else t for t in types)
in the__setitem__
method in themultimethod
class work?
This new version seems to work for some reason, allowing me to use Self
to refer to the current class:
if any(t is Self for t in types):
types = signature(inspect._findclass(func) if t is Self else t for t in types)
I'm not exactly sure why the above works but types = signature(inspect._findclass(func) if t is Self else t for t in types)
causes test_defaults
to fail with multimethod.DispatchError: ('func: 0 methods found', (<class 'int'>,), set())
...
Again, sorry for not quite understanding your earlier points about this!
I recommend putting aside multiple dispatch, and focusing on core Python features: __eq__
, isinstance
, and type
. What you want is probably something like:
class Base:
def __eq__(self, other):
return isinstance(other, Base) and self() == other()
I guess that's fair... Thanks for the advice, and sorry for the trouble!
Hello!
It seems that the
Self
type hint cannot be used withissubclass
; would you happen to have any suggestions on how to create a dispatched function that accepts an instance of the current class?Thank you kindly for the help!