賞金將在 6 小時后到期。此問題的答案有資格獲得 50聲望賞金。 rv.kvetch想引起更多關注這個問題:
我想回答兩個子問題。我如何確定類是否是通用的?正如 cmmnts MyTsetClass 中提到的不是真正的泛型,有沒有辦法我可以確定它來自 Generic/?例如。MyTsteClass.__origin__ <-- 是通用的 cls 是回傳 tru。
如果可能的話,還有什么是解決泛型型別的最佳方法?現在,如果我typing.get_Type_hins然后它回傳該型別的變數,但如果可能的話,需要將它們決議為它們的具體型別。腫瘤壞死因子
假設我們有一個通用的類定義,例如:
from dataclasses import dataclass
from typing import TypeVar, Generic, List
T1 = TypeVar('T1')
T2 = TypeVar('T2')
@dataclass
class MyGenericClass(Generic[T1, T2]):
val: T1
results: List[T2]
@dataclass
class BaseClass:
my_str: str
@dataclass
class MyTestClass(BaseClass, MyGenericClass[str, int]):
...
確定這MyTestClass是一個通用類的最佳方法是什么 - 即與常規資料類相反?
此外,typing在這種情況下,模塊是否提供了一種將泛型型別(TypeVar)決議為具體型別關系的簡單方法?
例如。上面給出results: List[T2]的,我想了解在將決議為型別T2的背景關系中。MyTestClassint
確定類是否是通用的
目前,如果我運行set(vars(MyTestClass)) - set(vars(BaseClass)),我會得到以下結果:
{'__parameters__', '__orig_bases__'}
但是我想知道是否typing提供了一種簡單的方法來確定一個類是泛型還是泛型類的子類,例如typing.Dict.
所以is_cls_generic()我會感興趣的效果是什么。
決議TypeVar型別
目前,當我打電話時typing.get_type_hints(MyTestClass),我得到以下結果:
{'val': ~T1, 'results': typing.List[~T2], 'my_str': <class 'str'>}
我想知道該typing模塊是否提供了一種簡單的方法來解決這些TypeVar變數,以便期望的結果是:
{'val': str, 'results': typing.List[int], 'my_str': str}
uj5u.com熱心網友回復:
學分
內省助手
mypy不提供您需要的功能,但手動實作這一點并不難。
# introspection.py
# mypy issue 776
import sys
from typing import get_args, get_origin, get_type_hints, Generic, Protocol
from typing import _collect_type_vars, _eval_type, _strip_annotations
def _generic_mro(result, tp):
origin = get_origin(tp)
if origin is None:
origin = tp
result[origin] = tp
if hasattr(origin, "__orig_bases__"):
parameters = _collect_type_vars(origin.__orig_bases__)
if origin is tp and parameters:
result[origin] = origin[parameters]
substitution = dict(zip(parameters, get_args(tp)))
for base in origin.__orig_bases__:
if get_origin(base) in result:
continue
base_parameters = getattr(base, "__parameters__", ())
if base_parameters:
base = base[tuple(substitution.get(p, p) for p in base_parameters)]
_generic_mro(result, base)
def generic_mro(tp):
origin = get_origin(tp)
if origin is None and not hasattr(tp, "__orig_bases__"):
if not isinstance(tp, type):
raise TypeError(f"{tp!r} is not a type or a generic alias")
return tp.__mro__
# sentinel value to avoid to subscript Generic and Protocol
result = {Generic: Generic, Protocol: Protocol}
_generic_mro(result, tp)
cls = origin if origin is not None else tp
return tuple(result.get(sub_cls, sub_cls) for sub_cls in cls.__mro__)
def _class_annotations(cls, globalns, localns):
hints = {}
if globalns is None:
base_globals = sys.modules[cls.__module__].__dict__
else:
base_globals = globalns
for name, value in cls.__dict__.get("__annotations__", {}).items():
if value is None:
value = type(None)
if isinstance(value, str):
value = ForwardRef(value, is_argument=False)
hints[name] = _eval_type(value, base_globals, localns)
return hints
# For brevety of the example, the implementation just add the substitute_type_vars
# implementation and default to get_type_hints. Of course, it would have to be directly
# integrated into get_type_hints
def get_type_hints2(
obj, globalns=None, localns=None, include_extras=False, substitute_type_vars=False
):
if substitute_type_vars and (isinstance(obj, type) or isinstance(get_origin(obj), type)):
hints = {}
for base in reversed(generic_mro(obj)):
origin = get_origin(base)
if hasattr(origin, "__orig_bases__"):
parameters = _collect_type_vars(origin.__orig_bases__)
substitution = dict(zip(parameters, get_args(base)))
annotations = _class_annotations(get_origin(base), globalns, localns)
for name, tp in annotations.items():
if isinstance(tp, TypeVar):
hints[name] = substitution.get(tp, tp)
elif tp_params := getattr(tp, "__parameters__", ()):
hints[name] = tp[
tuple(substitution.get(p, p) for p in tp_params)
]
else:
hints[name] = tp
else:
hints.update(_class_annotations(base, globalns, localns))
return (
hints
if include_extras
else {k: _strip_annotations(t) for k, t in hints.items()}
)
else:
return get_type_hints(obj, globalns, localns, include_extras)
# Generic classes that accept at least one parameter type.
# It works also for `Protocol`s that have at least one argument.
def is_generic_class(klass):
return hasattr(klass, '__orig_bases__') and getattr(klass, '__parameters__', None)
用法
from dataclasses import dataclass
from typing import TypeVar, Generic, List
from .introspection import get_type_hints2, is_generic_class
T1 = TypeVar('T1')
T2 = TypeVar('T2')
@dataclass
class MyGenericClass(Generic[T1, T2]):
val: T1
results: List[T2]
@dataclass
class BaseClass:
my_str: str
@dataclass
class MyTestClass(BaseClass, MyGenericClass[str, int]):
...
print(get_type_hints2(MyTestClass, substitute_type_vars=True))
# {'val': <class 'str'>, 'results': typing.List[int], 'my_str': <class 'str'>}
print(get_type_hints2(BaseClass, substitute_type_vars=True))
# {'my_str': <class 'str'>}
print(get_type_hints2(MyGenericClass, substitute_type_vars=True))
# {'val': ~T1, 'results': typing.List[~T2]}
print(is_generic_class(MyGenericClass))
# True
print(is_generic_class(MyTestClass))
# False
print(is_generic_class(BaseClass))
# False
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/481023.html
標籤:Python python-3.x 仿制药 蟒蛇打字
上一篇:如果超類是默認的,getDeclaredMethods()回傳繼承的方法
下一篇:子視窗上的DelphiVCL樣式
