You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
This is a bit sad. People would want to do some interactive experimentation to see what is issubclass(int, Union[int, str]), but probably there are some good reasons behind this decision.
Reacted by [object Object], Max Kühn, 林煒清(Lin Wei-Ching), sobolevn, Arun Joseph and Dominic Davis-Foster
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 acceptable(obj, hint) in typing.py that tells whether obj is OK for type hint. Like acceptable(42, Union[int, str]) == True.
Reacted by Derrick Chambers, Thierry Parmentelat, Mitar and Robert Smallshire
My remaining concern is the isinstance and issubclass support.
There is a real different difference between whether a value is a member of a type and whether it is an instance of a class.
Support for isinstance and issubclass applied to types just breeds confusion.
As you said, for most users, the distinction between types and classes is subtle. But I think it is important to make people aware that there is a distinction, even if they fully understand it.
For example,
List[int] and List[str] and mutually incompatible types, yet
isinstance([], List[int]) and isinstance([], List[str))
both return true.
Just delete all the __instancecheck__ and __subclasscheck__ methods and I'll be happy.
Maybe one could introduce a helper function acceptable(obj, hint) in typing.py that tells whether obj is OK for type hint. Like acceptable(42, Union[int, str]) == True.
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 issubclass() should probably be called is_consistent_with() (or some variation of that) to match the terminology used by Jeremy Siek in his Gradual Typing blog post (http://wphomes.soic.indiana.edu/jsiek/what-is-gradual-typing/). I'm not sure what to call the isinstance() equivalent, perhaps is_acceptable_for(). But I plan to ask others to contribute such functions.
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.
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 __subclasscheck__ working and not __isinstance__ ? I had a working runtime type checker (https://gist.github.com/agronholm/00311c169527442ddd5b) which relied on isinstance() but it broke at some point when __instancecheck__ was disabled. Should I not rely on even __subclasscheck__ then?
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 __instancecheck__ and __subclasscheck__ out of commission, how am I to implement a runtime type checker? I would need to be able to somehow detect that a type, say Dict[str, int] is derived from plain Dict, but I can't find any way to do that since issubclass(Dict[str, int], Dict) returns False. Likewise, I'd like to make use of the __extra__ argument to automatically check against the appropriate ABC when one is available, but I'm hesistant to just do getattr(obj, '__extra__', None) since __extra__ could be anything outside the typing module.
@bintoro This is clearly the case where practicality beats purity. I think it is not a good idea to force people to write
classIntNode(Node[int]):
pass
instead of just IntNode = Node[int] only from the point of view of purity. Moreover the type erasure is a widespread behavior in many languages, as said in PEP. So that here I agree with
That's all intentional, and the implementation somehow has to deal with it.
I think it is not a good idea to force people to write [...]
The point was that the validity of isinstance(x, IntNode) arguably shouldn't depend on the syntax by which IntNode was defined.
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. Initially I felt that, ideally, the consumer of the library shouldn't have to care if the class was internally defined as
MessageList=List[Message]
or
classMessageList(List[Message]): ...
But inevitably they do have to care. These things are not the same at all: one is an alias of List and the other is a subclass of List.
Simply preserving isinstance would solve nothing, since type erasure would bring about the seemingly bizarre outcome isinstance([], MessageList) == True in the alias case.
I suppose the correct answer is that a library shouldn't advertise MessageList as a class if it's really just a type alias. In general, exposing type aliases requires care because then the consumer must be aware of how they work.
I suppose the correct answer is that a library shouldn't advertise MessageList as a class if it's really just a type alias. In general, exposing type aliases requires care because then the consumer must be aware of how they work.
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.
"The best I can recommend is using __origin__ -- if we were to change this attribute there would still have to be some other way to access the same information, and it would be easy to grep your code for occurrences of __origin__."
Well, it seems you did change it. As related in the RH bug, in Python 3.7, typing.Tuple[int, str].__origin__ is no longer the class typing.Tuple, but the class tuple. Per the quote above, there ought now to be "some other way to access the same information", but I'm buggered if I can find it - any hints? So far the best I came up with is a hideous string comparison (see https://bugzilla.redhat.com/show_bug.cgi?id=1598574#c1 ). Thanks!
You can get the actual typing object using something like this assert typing.__dict__[Tuple[int, str]._name] is typing.Tuple. Just be sure to check ._name is not None. It is None for most things, except List, Tuple, and few others.
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.
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).
Activity
ilevkivskyi commentedon May 22, 2015
This is a bit sad. People would want to do some interactive experimentation to see what is
issubclass(int, Union[int, str]), but probably there are some good reasons behind this decision.1st1 commentedon May 22, 2015
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.
ilevkivskyi commentedon May 22, 2015
Maybe one could introduce a helper function
acceptable(obj, hint)in typing.py that tells whetherobjis OK for typehint. Likeacceptable(42, Union[int, str]) == True.gvanrossum commentedon May 22, 2015
Here's what Mark wrote about the subject:
1st1 commentedon May 22, 2015
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.
gvanrossum commentedon May 22, 2015
The equivalent of
issubclass()should probably be calledis_consistent_with()(or some variation of that) to match the terminology used by Jeremy Siek in his Gradual Typing blog post (http://wphomes.soic.indiana.edu/jsiek/what-is-gradual-typing/). I'm not sure what to call theisinstance()equivalent, perhapsis_acceptable_for(). But I plan to ask others to contribute such functions.ilevkivskyi commentedon May 22, 2015
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.
ilevkivskyi commentedon May 22, 2015
@gvanrossum, Indeed, to have two such functions would be very cool. Even their presence would underline the distinction between the classes and types.
NYKevin commentedon Jun 5, 2015
If we're drawing this type/class distinction, PEP 483 should be updated:
Should I report that as a separate bug?
gvanrossum commentedon Jun 5, 2015
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).
agronholm commentedon Aug 21, 2015
I'm confused -- as Python 3.5 is now in RC, does this mean the typing types were really left with only
__subclasscheck__working and not__isinstance__? I had a working runtime type checker (https://gist.github.com/agronholm/00311c169527442ddd5b) which relied on isinstance() but it broke at some point when__instancecheck__was disabled. Should I not rely on even__subclasscheck__then?gvanrossum commentedon Aug 21, 2015
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.
agronholm commentedon Sep 7, 2015
Ok, so with both
__instancecheck__and__subclasscheck__out of commission, how am I to implement a runtime type checker? I would need to be able to somehow detect that a type, say Dict[str, int] is derived from plain Dict, but I can't find any way to do that since issubclass(Dict[str, int], Dict) returns False. Likewise, I'd like to make use of the__extra__argument to automatically check against the appropriate ABC when one is available, but I'm hesistant to just do getattr(obj, '__extra__', None) since__extra__could be anything outside the typing module.38 remaining items
ilevkivskyi commentedon May 6, 2016
@bintoro This is clearly the case where practicality beats purity. I think it is not a good idea to force people to write
instead of just
IntNode = Node[int]only from the point of view of purity. Moreover the type erasure is a widespread behavior in many languages, as said in PEP. So that here I agree withbintoro commentedon May 7, 2016
The point was that the validity of
isinstance(x, IntNode)arguably shouldn't depend on the syntax by whichIntNodewas defined.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. Initially I felt that, ideally, the consumer of the library shouldn't have to care if the class was internally defined asor
But inevitably they do have to care. These things are not the same at all: one is an alias of
Listand the other is a subclass ofList.Simply preserving
isinstancewould solve nothing, since type erasure would bring about the seemingly bizarre outcomeisinstance([], MessageList) == Truein the alias case.I suppose the correct answer is that a library shouldn't advertise
MessageListas a class if it's really just a type alias. In general, exposing type aliases requires care because then the consumer must be aware of how they work.ilevkivskyi commentedon May 7, 2016
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.
Started python#136
Started python#136
More work on python#136
Finish first round of python#136
Kill __subclasscheck__ (#283)
AdamWill commentedon Jul 5, 2018
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
__origin__-- if we were to change this attribute there would still have to be some other way to access the same information, and it would be easy to grep your code for occurrences of__origin__."Well, it seems you did change it. As related in the RH bug, in Python 3.7,
typing.Tuple[int, str].__origin__is no longer the classtyping.Tuple, but the classtuple. Per the quote above, there ought now to be "some other way to access the same information", but I'm buggered if I can find it - any hints? So far the best I came up with is a hideous string comparison (see https://bugzilla.redhat.com/show_bug.cgi?id=1598574#c1 ). Thanks!JelleZijlstra commentedon Jul 5, 2018
You should probably use https://github.com/ilevkivskyi/typing_inspect.
AdamWill commentedon Jul 5, 2018
@JelleZijlstra thanks, we'd have to package it and add it to anaconda's deps...
edit: also, the
get_origindocstring seems to suggest it doesn't work for several types we use, likeListandDict.ilevkivskyi commentedon Jul 6, 2018
You can get the actual typing object using something like this
assert typing.__dict__[Tuple[int, str]._name] is typing.Tuple. Just be sure to check._name is not None. It isNonefor most things, exceptList,Tuple, and few others.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.
AdamWill commentedon Jul 6, 2018
@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).
ilevkivskyi commentedon Jul 6, 2018
OK, I see. Let me know if you need more help with this.