Python3 typehints - 传入类型元组后,指定 return 值是这些类型实例的元组
Python3 typehints - After passing in a Tuple of Types, specify that the return value is a Tuple of instances of those Types
我目前为 "shortcut" 函数使用了一些复杂的类型提示,我用 sqlalchemy
调用了 dB。例如,不必写,
users: List[User] = User.query.all()
我在我的基础模型中创建了一个快捷函数,
@classmethod
def qall(cls: Type[T_DBModel]) -> List[T_DBModel]:
cls.query.all()
所以现在我可以只写 users = User.qall()
并且类型提示对我的 IDE (PyCharm) 来说就像一个魅力 - 它正确地识别出这将是 List[User]
无需我指定。
不过现在,我想对 sqlalchemy
的 with_entities
函数执行相同的操作。有了它,您可以指定您希望 dB 调用 return 事物的元组,即
users_roles: List[Tuple[User, Role]] = User.query.with_entities(User, Role).all()
我想为此写一个类似上面的快捷方式,
@classmethod
def qwith_entities(cls: Type[T_DBModel], retvals: T) -> List[T]:
cls.query.with_entities(*retvals).all()
所以我可以"shortcut"以同样的方式使用它,
users_roles = User.qwith_entities((User, Role))
问题是,使用该签名,而不是类型提示指定返回 List[Tuple[User, Role]]
,它是 List[Tuple[Type[User], Type[Role]]]
,这是不正确的,也不是 return 值。
如果我把它分解成多个函数,那一切都很好,
@classmethod
def qwith_entity(cls: Type[T_DBModel], retval: Type[T]) -> List[T]:
cls.query.with_entities(retval).all()
它知道 Base.qwith_entity(User)
将是 List[User]
(你永远不会这样做,只是一个例子)和
@classmethod
def qwith_2_entities(cls: Type[T_DBModel], retval_1: Type[T], retval_2: Type[Y]) -> List[Tuple[T, Y]]:
cls.query.with_entities(retval_1, retval_2).all()
或
@classmethod
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T], Type[Y]]) -> List[Tuple[T, Y]]:
cls.query.with_entities(*retvals).all()
谁知道 users_roles = Base.qwith_2_entities((User, Role))
会是 List[Tuple[User, Role]]
但我不知道该怎么做,也不知道是否可以正确地键入不同 Type
的 变量 长度 Tuple
,以及return value 应该解压缩,即一些愚蠢的东西,
@classmethod
def qwith_entities(cls: Type[T_DBModel], retvals: Tuple[Type[...T]]) -> List[Tuple[T]]:
cls.query.with_entities(*retvals).all()
您需要 variadic generics 才能准确拼出签名; 这还不可能,但它可能看起来像:
Ts = TypeVar('Ts', variadic=True)
@classmethod
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[Ts], ...]) -> List[Tuple[Ts, ...]]:
cls.query.with_entities(*retvals).all()
其中 Ts
TypeVar
是可变的,Tuple[Type[Ts], ...]
扩展为 Tuple[Type[T_0], Type[T_1], Type[T_2], ...])
并且返回列表中的类型扩展为 Tuple[T_0, T_1, T_2, ...])
但是,如前所述,这还不是可用的语法。解决方法是将 @overload
s 与 1、2、3 等不同的 TypeVar
s 一起使用,至少足以满足您的所有用例:
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T3 = TypeVar('T3')
T4 = TypeVar('T4')
# add more as needed
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1]]) -> List[Tuple[T1]]:
pass
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1], Type[T2]]) -> List[Tuple[T1, T2]]:
pass
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1], Type[T2], Type[T3]]) -> List[Tuple[T1, T2, T3]]:
pass
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1], Type[T2], Type[T3], Type[T4]]) -> List[Tuple[T1, T2, T3, T4]]:
pass
# add more overloads as needed
@classmethod
def qwith_2_entities(cls, retvals):
cls.query.with_entities(*retvals).all()
我目前为 "shortcut" 函数使用了一些复杂的类型提示,我用 sqlalchemy
调用了 dB。例如,不必写,
users: List[User] = User.query.all()
我在我的基础模型中创建了一个快捷函数,
@classmethod
def qall(cls: Type[T_DBModel]) -> List[T_DBModel]:
cls.query.all()
所以现在我可以只写 users = User.qall()
并且类型提示对我的 IDE (PyCharm) 来说就像一个魅力 - 它正确地识别出这将是 List[User]
无需我指定。
不过现在,我想对 sqlalchemy
的 with_entities
函数执行相同的操作。有了它,您可以指定您希望 dB 调用 return 事物的元组,即
users_roles: List[Tuple[User, Role]] = User.query.with_entities(User, Role).all()
我想为此写一个类似上面的快捷方式,
@classmethod
def qwith_entities(cls: Type[T_DBModel], retvals: T) -> List[T]:
cls.query.with_entities(*retvals).all()
所以我可以"shortcut"以同样的方式使用它,
users_roles = User.qwith_entities((User, Role))
问题是,使用该签名,而不是类型提示指定返回 List[Tuple[User, Role]]
,它是 List[Tuple[Type[User], Type[Role]]]
,这是不正确的,也不是 return 值。
如果我把它分解成多个函数,那一切都很好,
@classmethod
def qwith_entity(cls: Type[T_DBModel], retval: Type[T]) -> List[T]:
cls.query.with_entities(retval).all()
它知道 Base.qwith_entity(User)
将是 List[User]
(你永远不会这样做,只是一个例子)和
@classmethod
def qwith_2_entities(cls: Type[T_DBModel], retval_1: Type[T], retval_2: Type[Y]) -> List[Tuple[T, Y]]:
cls.query.with_entities(retval_1, retval_2).all()
或
@classmethod
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T], Type[Y]]) -> List[Tuple[T, Y]]:
cls.query.with_entities(*retvals).all()
谁知道 users_roles = Base.qwith_2_entities((User, Role))
会是 List[Tuple[User, Role]]
但我不知道该怎么做,也不知道是否可以正确地键入不同 Type
的 变量 长度 Tuple
,以及return value 应该解压缩,即一些愚蠢的东西,
@classmethod
def qwith_entities(cls: Type[T_DBModel], retvals: Tuple[Type[...T]]) -> List[Tuple[T]]:
cls.query.with_entities(*retvals).all()
您需要 variadic generics 才能准确拼出签名; 这还不可能,但它可能看起来像:
Ts = TypeVar('Ts', variadic=True)
@classmethod
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[Ts], ...]) -> List[Tuple[Ts, ...]]:
cls.query.with_entities(*retvals).all()
其中 Ts
TypeVar
是可变的,Tuple[Type[Ts], ...]
扩展为 Tuple[Type[T_0], Type[T_1], Type[T_2], ...])
并且返回列表中的类型扩展为 Tuple[T_0, T_1, T_2, ...])
但是,如前所述,这还不是可用的语法。解决方法是将 @overload
s 与 1、2、3 等不同的 TypeVar
s 一起使用,至少足以满足您的所有用例:
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T3 = TypeVar('T3')
T4 = TypeVar('T4')
# add more as needed
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1]]) -> List[Tuple[T1]]:
pass
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1], Type[T2]]) -> List[Tuple[T1, T2]]:
pass
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1], Type[T2], Type[T3]]) -> List[Tuple[T1, T2, T3]]:
pass
@overload
def qwith_2_entities(cls: Type[T_DBModel], retvals: Tuple[Type[T1], Type[T2], Type[T3], Type[T4]]) -> List[Tuple[T1, T2, T3, T4]]:
pass
# add more overloads as needed
@classmethod
def qwith_2_entities(cls, retvals):
cls.query.with_entities(*retvals).all()