-
Notifications
You must be signed in to change notification settings - Fork 250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kill __subclasscheck__ #136
Comments
This is a bit sad. People would want to do some interactive experimentation to see what is |
Maybe it is a good thing, at least for 3.5. This will effectively force type objects to be used only in annotations, which gives us more room to tweak their behaviour before 3.6. |
Maybe one could introduce a helper function |
Here's what Mark wrote about the subject:
|
I think that we should leave the task of validating types to external tools (and compilers), not user code. So I'd be -1 on this. |
The equivalent of |
The intended use would be not to validate types in code but just do some quick interactive tests in REPL. But OK, maybe you are right people anyway will start using it for validation. |
@gvanrossum, Indeed, to have two such functions would be very cool. Even their presence would underline the distinction between the classes and types. |
If we're drawing this type/class distinction, PEP 483 should be updated:
Should I report that as a separate bug? |
Here is fine. I've made some updates to PEP 483; it really does use the two words interchangeably, and I don't want to have to update the text too much, but I elaborated that particular sentence (and removed the thing about class, which is irrelevant). |
I'm confused -- as Python 3.5 is now in RC, does this mean the typing types were really left with only |
You should not rely on subclass checking either. I ran out of time, but PEP 484 is accepted provisionally, which means we can still change the API in later 3.5.x releases or in 3.6. |
Ok, so with both |
The idea is that you would have to write your own functions similar to isinstance() and issubclass() to introspect the objects created at run-time by type annotations. You are right however that the introspection interface has not yet been specified -- I think it would have to be a separate PEP. I would not rely on the |
Alright, so I guess this means runtime type checking has to wait until that introspection interface has been specified. FWIW, here's what I had before I ran into this problem: https://gist.github.com/agronholm/b06bdba54c73d9b2f1f1 |
I do encourage you to continue along this path, assuming the introspection API won't be terribly different from what is currently implemented. (In fact I think extra is probably the only thing that might significantly change, as it isn't very principled.) Instead of issubclass() and isinstance() you'll have to code your own, but looking at parameters etc. sounds about right. Have you thought about what to do about requiring that type variables conform across parameters and return values yet? E.g. for |
I had thought about type variable checking but I hadn't gotten that far yet. The problem I was stuck with is that if I encounter a type hint like |
The best I can recommend is using |
I'll look at them -- thanks! |
OK, delivered: https://pypi.python.org/pypi/typeguard |
See also http://bugs.python.org/issue26075 (Union[str, Iterable[int]] returns Iterable[int], which is wrong!) |
I have just uploaded the new version of my runtime type checker, Compared to typeguard 1.1.1, it has broader support (except for Callable, which is yet missing) and a more precise documentation of its semantics and limitations. I struggled enormously with the semantics of |
I think I'll wait until 3.5.2 is released to get back to this.
|
@ilevkivskyi It would be pretty easy to incorporate this in #207, I think. I'll add one more note here. Assuming parameterized generics now become types (non-classes), then something that needs discussion is what to do about instantiating them. There are examples of this in the PEP: IntNode = Node[int]
StrNode = Node[str]
p = IntNode()
q = StrNode() If class IntNode(Node[int]):
pass
p = IntNode() |
Those examples should work. However, even though this would be equivalent at run time:
that's disallowed by the PEP and indeed mypy reports it as an error (but That's all intentional, and the implementation somehow has to deal with it. |
@bintoro This is clearly the case where practicality beats purity. I think it is not a good idea to force people to write class IntNode(Node[int]):
pass instead of just
|
The point was that the validity of However, upon further reflection, I think I have to withdraw this complaint, because the two syntaxes should not be construed as substitutes for each other. Consider a case where a library provides a class named MessageList = List[Message] or class MessageList(List[Message]): ... But inevitably they do have to care. These things are not the same at all: one is an alias of Simply preserving I suppose the correct answer is that a library shouldn't advertise |
This is a good point, If you think that the language in the PEP is too loose, then propose a modification to tighten it, so that this is clear. |
This PR: - Fixes #136 - Fixes #133 - Partially addresses #203 (fixes the isinstance part, and multiple inheritance, still typing.Something is not a drop-in replacement for collections.abc.Something in terms of implementation). - Also fixes http://bugs.python.org/issue26075, http://bugs.python.org/issue25830, and http://bugs.python.org/issue26477 - Makes almost everything up to 10x faster. - Is aimed to be a minimalistic change. I only removed issubclass tests from test_typing and main changes to typing are __new__ and __getitem__. The idea is to make most things not classes. Now _ForwardRef(), TypeVar(), Union[], Tuple[], Callable[] are not classes (i.e. new class objects are almost never created by typing). Using isinstance() or issubclass() rises TypeError for almost everything. There are exceptions: Unsubscripted generics are still OK, e.g. issubclass({}, typing.Mapping). This is done to (a) not break existing code by addition of type information; (b) to allow using typing classes as a replacement for collections.abc in class and instance checks. Finally, there is an agreement that a generic without parameters assumes Any, and Any means fallback to dynamic typing. isinstance(lambda x: x, typing.Callable) is also OK. Although Callable is not a generic class, when unsubscribed, it could be also used as a replacement for collections.abc.Callable. The first rule for generics makes isinstance([], typing.List) possible, for consistency I also allowed isinstance((), typing.Tuple). Finally, generics should be classes, to allow subclassing, but now the outcome of __getitem__ on classes is cached. I use an extended version of functools.lru_cache that allows fallback to non-cached version for unhashable arguments.
I just got here via https://stackoverflow.com/questions/49171189/whats-the-correct-way-to-check-if-an-object-is-a-typing-generic and https://bugzilla.redhat.com/show_bug.cgi?id=1598574 . The SO thread notes this quote from @gvanrossum above: "The best I can recommend is using Well, it seems you did change it. As related in the RH bug, in Python 3.7, |
You should probably use https://github.com/ilevkivskyi/typing_inspect. |
@JelleZijlstra thanks, we'd have to package it and add it to anaconda's deps... edit: also, the |
You can get the actual typing object using something like this But in long term perspective, I would not recommend depending on private internal APIs. If you are interested in inspection of typing objects, you can submit a feature request for this, it looks like more people than expected are interested in this. Maybe we can provide something in Python 3.8. |
@ilevkivskyi thanks for the suggestion! I mean, it's possible this code is doing something 'silly' in the first place; I didn't write it and I haven't yet looked at whether what it's doing actually makes a lot of sense or if there'd be some better alternative. For now I was just focusing on the direct issue as it's an urgent problem for us (Fedora). |
OK, I see. Let me know if you need more help with this. |
Mark Shannon wants me to drop
__subclasscheck__
from all type objects (Any, Union etc.). This is somewhat major surgery since it is used by Union simplification and for various type checks. See also #133 and #135.The text was updated successfully, but these errors were encountered: