@gmdzy2010 Mypy is fine with your code. Perhaps it’s a Pyright issue.
mypy self_check.py
Success: no issues found in 1 source file
@FelixFourcolor
This would make Self no more useful than hardcoding the name of the class (A) into the annotation (albeit more maintainable). Self is a lot more useful than that, and subclasses are specifically catered for.
Perhaps you meant that a=A(); a.test(B()) would fail type-checking?
from typing import Self, reveal_type
class Foo:
def return_self(self) -> Self:
...
return self
class SubclassOfFoo(Foo): pass
reveal_type(Foo().return_self()) # Revealed type is "Foo"
reveal_type(SubclassOfFoo().return_self()) # Revealed type is "SubclassOfFoo"
@JamesParrott I suppose that’s mypy’s fault, because I don’t think the code is valid. Consider
class B(A):
pass
b = B()
b.test()
instance = b.a_instances[0]
reveal_type(instance)
What is this type? The a_instances is declared as list[Self], so the result should be a Self, i.e, B. But test() appends an A.
Your example doesn’t demonstrate what I’m talking about. This method return self, so the annotation is -> Self as it should be. What I’m talking about is more akin to this:
class Foo:
def return_self(self):
return Foo()
You can’t annotate this method -> Self, because it returns Foo which is not Self for child classes. Similarly for OP’s question, they don’t return but append to a list, but it’s the same idea.
I don’t know anything about Self, or what you mean A to be, but unless you expect A to be a tree, I would expect a_instances to be a class attribute.
I don’t find “correctness” in the form of Python type hinting to be half as helpful, as it is in the form of using ABCs or protocols, from the point of view of expressing intent. And even then, I don’t think correctness is particularly helpful at all. Python’s a dynamic language… But my opinion for what it’s worth:
The programmer can both choose to hardcode .test to append A(), and type hint a_instances as Self with no harm done, only if they do not support, and never intend to subclass A.
If they want to subclass A (or if A is part of a library API, whose downstream users may quite reasonably wish to subclass A), and append subclasses of A, then yes indeedy, they should either change the annotation to List[A], or .test should append self.__class__() instead (if the Self type hint is to be kept).
Alternatively, perhaps the whole point of .test is that the test fails for subclasses? If that’s what the programmer wants to test, then Python allows that.