-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Support recursive types #731
Comments
If (or when) mypy will have structural subtyping, recursive types would also be useful there. |
My current plan is to postpone recursive types until simple structural subtyping is in and reconsider them later. After thinking about them more they are going to increase complexity a lot of I haven't seen much evidence for them being needed that often. |
If I'm understanding this issue right, I'm running into it for classes that want a fluent interface. So for example, if I want callers to do something like this: myfoo.add(bar).add(baz).finish() Then the definition of the class Foo:
def add(self, x) -> Foo: # Python chokes on this line!
# do stuff
return self Another place where Python commonly does |
@oconnor663 Try: class Foo:
def add(self, x) -> 'Foo':
# do stuff
return self |
Ah, thank you. |
@kirbyfan64, do you know if there are standard functions anywhere that understand this convention? Like, if I wanted to introspect a couple functions and compare the types of their arguments, should I handle the |
@oconnor663 I don't think there's anything like that. If you're introspecting the functions via a decorator, you could try accessing the caller's globals and locals. |
You're aware of typing.get_type_hints(obj) There used to be an instance() implementation in typing.py but Mark Shannon On Fri, Oct 16, 2015 at 9:37 AM, Ryan Gonzalez notifications@github.com
--Guido van Rossum (python.org/~guido) |
@gvanrossum that's exactly what I was looking for, thanks. Sorry for the n00b questions today, but awesome that all this is supported. |
Mypy should detect missing string literal escapes (see #948). |
Going back to the original point on the issue, I found a case in the stdlib where this would be needed; the type for def isinstance(o: object, t: Union[type, Tuple[type, ...]]) -> bool: ... but it should actually be: ClassInfo = Union[type, Tuple['ClassInfo', ...]]
def isinstance(o: object, t: ClassInfo) -> bool: ... Because according to https://docs.python.org/3/library/functions.html#isinstance the tuples can be nested. I found an actual example of this while typechecking |
Mypy doesn't support recursive types yet, so we can't properly express TSerializable nested structures. For now, we just disable type checking in the appropriate locations. python/mypy#731
I have come across this while trying to define a generic JSON type:
So consider this a +1 for supporting this use case. |
@srittau JSON needs to be Any because it is recursive and you can give json.loads a custom JSONEncoder class: _PlainJSON = Union[Dict[str, "_PlainJSON"], List["_PlainJSON"], str, int, float, bool, None]
_T = TypeVar('_T')
JSON = Union[_PlainJSON, _T, Dict[str, "JSON"], List["JSON"]]
def loads(data: str, cls: Type[JSONEncoder[_T]]) -> JSON: ... of course recursive types and |
The following pattern seems to be good enough for my purposes. The boilerplate is tolerable for me.
|
Latest version of pattern. We use this example at Legalese for interacting with SMT solvers (the SMTLIB language). I found that I ended up forgetting to use the typed
|
Already supported in current Mypy: python/mypy#731. The definition of DumperKey was wrong anyway, in a way causing mypy to crash: see python/mypy#14000.
It appears that v0.990/v0.991 may not have addressed the entirety of the challenge that is recursive/cyclic types: #14219 |
For those reading in posterity:
So with |
It doesn't work in this case: from collections.abc import Sequence
from typing import TypeAlias
FloatVector: TypeAlias = Sequence[float]
FloatTensor: TypeAlias = FloatVector | Sequence["FloatTensor"]
rejected_float_vector: FloatVector = "ok" # OK: rejected
accepted_float_tensor: FloatTensor = [[[3.14]]] # OK: accepted
rejected_float_vector1: FloatTensor = object() # OK: rejected
rejected_float_vector2: FloatTensor = "fail" # FAIL: accepted https://mypy-play.net/?mypy=latest&python=3.12&flags=strict&gist=da0434e6062956cfd667a9e8c8bd3ff9 |
@jorenham Thanks for the report! Can you please open a new issue? |
@jorenham Beware that this EDIT: we would need inductive types. If Tensor = Sequence[float] | Map[Sequence, Tensor] |
In numpy the current maximum number of dimensions is 64, so that would indeed be possible. But in order to keep error messages from getting to long, and the type-checking from becoming to slow, I decided to go for this concise yet "broader" approach instead. |
This made me realize that some of the numpy array-like type aliases in |
The following in particular would be useful:
The text was updated successfully, but these errors were encountered: