Cherry
Cherry

Reputation: 33598

How use @multimethod and Self tohether in python?

Consider the code:

from enum import Enum, auto
from typing import Self
from typing import List

from multipledispatch import dispatch
from multimethod import multimethod


class Name:
    __id: list[str]

    def __new__(self, id: list[str]):
        self.__id = id

    # ...

    @multimethod
    def prefix(self, other: Self) -> Self:
        return self.prefix(other.__id)

    # EXCEPTION HERE
    @multimethod
    def prefix(self, prefix: List[str]) -> Self:
        return Name(prefix + self.__id)

    @multimethod
    def postfix(self, postfix: List[str]) -> Self:
        return Name(self.__id + postfix)

Error stack is

Traceback (most recent call last):
  File "myfolder\app.py", line 6, in <module>
    from my_package import MyClass
  File "myfolder\__init__.py", line 13, in <module>
    class Name:
  File "myfolder\__init__.py", line 50, in Name
    @multimethod
     ^^^^^^^^^^^
  File "myfolder\.venv\Lib\site-packages\multimethod\__init__.py", line 257, in __init__
    self[signature.from_hints(func)] = func
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "myfolder\.venv\Lib\site-packages\multimethod\__init__.py", line 299, in __setitem__
    parents = types.parents = self.parents(types)
                              ^^^^^^^^^^^^^^^^^^^
  File "myfolder\.venv\Lib\site-packages\multimethod\__init__.py", line 282, in parents
    parents = {key for key in list(self) if isinstance(key, signature) and key < types}
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "myfolder\.venv\Lib\site-packages\multimethod\__init__.py", line 282, in <setcomp>
    parents = {key for key in list(self) if isinstance(key, signature) and key < types}
                                                                           ^^^^^^^^^^^
  File "myfolder\.venv\Lib\site-packages\multimethod\__init__.py", line 221, in __lt__
    return self != other and self <= other
                             ^^^^^^^^^^^^^
  File "myfolder\.venv\Lib\site-packages\multimethod\__init__.py", line 218, in __le__
    return self.required <= len(other) and all(map(issubclass, other, self))
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\work\tools\Python\Python3.11.3\Lib\typing.py", line 466, in __subclasscheck__
    raise TypeError(f"{self} cannot be used with issubclass()")
TypeError: typing.Self cannot be used with issubclass()

Why this happended? May I use Self return type with @multimethod?

Python version 3.11.3

Upvotes: -1

Views: 28

Answers (1)

Dunes
Dunes

Reputation: 40778

You cannot use Self as any type annotation you use must support being used in issubclass() calls. Some typing constructs are special-cased (such as Union), but Self is not among these special-cased types.

If you want to type a parameter as being the type of the class being defined then you can add those methods outside, and after, the main body of the class. When adding methods in such a way use the register() method instead. For example:

class Name:
    @multimethod
    def func(self, x: int) -> int:
        print('f(int)')
        return 123

@Name.func.register
def _(self, x: Name) -> Name:
    print('f(Name)')
    return Name()

assert Name().func(0) == 123
assert Name().func(Name()).__class__ is Name

Upvotes: 0

Related Questions