Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the correct way to check if an object is a typing.Generic?

I'm trying to write code that validates type hints, and in order to do so I have to find out what kind of object the annotation is. For example, consider this snippet that's supposed to tell the user what kind of value is expected:

import typing  typ = typing.Union[int, str]  if issubclass(typ, typing.Union):     print('value type should be one of', typ.__args__) elif issubclass(typ, typing.Generic):     print('value type should be a structure of', typ.__args__[0]) else:     print('value type should be', typ) 

This should print "value type should be one of (int, str)", but instead it throws an exception:

Traceback (most recent call last):   File "untitled.py", line 6, in <module>     if issubclass(typ, typing.Union):   File "C:\Python34\lib\site-packages\typing.py", line 829, in __subclasscheck__     raise TypeError("Unions cannot be used with issubclass().") TypeError: Unions cannot be used with issubclass(). 

isinstance doesn't work either:

>>> isinstance(typ, typing.Union) Traceback (most recent call last):   File "<stdin>", line 1, in <module>   File "C:\Python34\lib\site-packages\typing.py", line 826, in __instancecheck__     raise TypeError("Unions cannot be used with isinstance().") TypeError: Unions cannot be used with isinstance(). 

What's the correct way to check if typ is a typing.Generic?

If possible, I would like to see a solution that's backed by documentation or a PEP or some other resource. A "solution" that "works" by accessing undocumented, internal attributes is easy to find. But more likely than not, it'll turn out to be an implementation detail and will change in future versions. I'm looking for "the right way" to do it.

like image 489
Aran-Fey Avatar asked Mar 08 '18 10:03

Aran-Fey


People also ask

What is typing generic?

Essentially, generic types allow you to write a general, generic class (or method) that works with different types, allowing for code re-use. Rather than specifying obj to be of an int type, or a String type, or any other type, you define the Box class to accept a type parameter < ;T>.

Is type of generic C#?

Generic means the general form, not specific. In C#, generic means not specific to a particular data type. C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, and operators using the type parameter and without the specific data type.


1 Answers

You may be looking for __origin__:

# * __origin__ keeps a reference to a type that was subscripted, #   e.g., Union[T, int].__origin__ == Union;` 
import typing  typ = typing.Union[int, str]  if typ.__origin__ is typing.Union:     print('value type should be one of', typ.__args__) elif typ.__origin__ is typing.Generic:     print('value type should be a structure of', typ.__args__[0]) else:     print('value type should be', typ)  >>>value type should be one of (<class 'int'>, <class 'str'>) 

The best I could find to advocate the use of this undocumented attribute is this reassuring quote from Guido Van Rossum (2 years ago):

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__. (I'd be less worried about changes to __origin__ than to __extra__.) You may also look at the internal functions _gorg() and _geqv() (these names will not be part of any public API, obviously, but their implementations are very simple and conceptually useful).

This caveat in the documentation seem to indicate that nothing is set in marble yet:

New features might be added and API may change even between minor releases if deemed necessary by the core developers.

like image 198
Jacques Gaudin Avatar answered Oct 12 '22 10:10

Jacques Gaudin