我正在尝试用 Python 创建代数,但发现创建参数化类很困难。
作为一个例子,考虑这个ProductWeight类。它包含另外两个Weight对象,具有强制类型(至少静态地,通过mypy)。
这将失败,因为(根据设计)我无法访问类W1并W2调用它们的类方法,例如zero. (它们没有指定;ProductWeight没有模板化。)ProductWeight当我创建实例时,不知道要绑定到它的类型。
from typing import Generic, TypeVar
W1 = TypeVar("W1")
W2 = TypeVar("W2")
class ProductWeight(Generic[W1, W2]):
def __init__(self, value1: W1, value2: W2):
self.value1_ = value1
self.value2_ = value2
@classmethod
def zero(cls):
return cls(W1.zero(), W2.zero()) # Will fail - no access to W1 and W2.
Run Code Online (Sandbox Code Playgroud)
相比之下,这在 C++ 中很简单:因为类型是参数化的,所以它能够查找W1::Zero.
template<typename W1, typename W2>
public:
ProductWeight(W1 w1, W2 w2) : value1_(w1), …Run Code Online (Sandbox Code Playgroud) 我正在尝试完成以下任务(请参阅mypy Playground):
from typing import TypedDict, Final
account_schema: Final = {"name": str, "email": str}
Account = TypedDict("Account", account_schema)
AccountPatch = TypedDict("AccountPatch", account_schema, total=False)
Run Code Online (Sandbox Code Playgroud)
我的想法是,我可以在一个地方指定我的模式,一个版本需要所有字段(Account插入数据库时),另一个版本使所有字段可选(AccountPatch更新数据库时)。
来自PEP 586:
限定符
Final用作声明变量有效的简写Literal。
但mypy错误如下:
error: TypedDict() expects a dictionary literal as the second argument
Run Code Online (Sandbox Code Playgroud)
为什么不允许TypedDict字典Final作为其第二个参数?
对于我的核心问题,我是否可以对两个TypedDicts 使用相同的架构(一个具有整体性,一个不具有整体性),而不必复制架构?
我遇到了里氏替换原则的问题,并且不太确定解决它的最佳方法是什么。
有问题的代码
class BaseModel:
def run(self, base_model_input: BaseModelInput) -> BaseModelOutput:
"""Throws NotImplemented or @abstractmethod"""
pass
class SpecificModel(BaseModel):
def run(self, specific_input: SpecificModelInput) -> SpecificModelOutput:
# do things...
Run Code Online (Sandbox Code Playgroud)
我很清楚为什么这不是一个很好的代码,以及为什么它违反了里氏替换原则。我想知道如何更好地设计我的系统以避免这个问题。
从根本上讲,我有一个BaseModel类似于接口的类,提供一些run扩展类必须实现的方法。但是扩展类还处理特定的输入/输出,它们也是基本输入/输出类的扩展(继承SpecificModelInput并BaseModelInput添加一些字段和功能,与输出相同)
这里更好的方法是什么?
python design-patterns liskov-substitution-principle python-3.x python-typing
编辑注释 1:到目前为止,我发现PEP 612解决了这个问题 - 从 Python 3.10 开始 - 通过引入typing.ParamSpec. 所以这个问题专门针对 Python 3.9 或更早版本。
编辑注释 2:原始示例过于狭窄,因为它的返回类型与参数类型完全匹配,但问题实际上是关于更通用的情况,其中函数的参数签名相同,但返回类型相同是不同的。(也欢迎允许不同参数签名的更通用的解决方案。)
问题:我正在使用一个转换函数,它接收一个函数作为参数,并返回另一个函数作为其结果。传递的函数可以有任意数量和类型的参数(为简单起见,我们可以坚持位置参数),返回的函数以与原始函数相同的方式调用(具有相同数量和类型的参数),并有一个返回值type 取决于传递函数的返回类型(但不一定等于它;例如,它可以是包含原始返回类型的值和某个给定类型的另一个值的元组)。
如何以反映传递和返回函数的签名依赖性的方式注释转换函数?
一个简单的例子:
from typing import Callable
def transform(original_function: Callable) -> Callable:
def new_function(*args):
extra_payload = <do some calculation>
return original_function(*args), extra_payload
return new_function
def f(x: int, s: str) -> bool:
...
f(3, 'abc') # this is a valid call
f('abc', 3) # PyCharm warns about wrong argument types
# The goal is to have a …Run Code Online (Sandbox Code Playgroud) python annotations type-hinting higher-order-functions python-typing
我正在尝试使用 Python 3.8 中的输入,但有点卡住了。示例:我主要在main.py. 我还有一个类util.py,其中包含一些辅助函数和类。但这些类还需要从main.pyTyping 导入类。现在,当我想使用util.pyin中的函数时main.py中的函数时,我还需要导入它 - 但随后我会因为循环导入而收到错误(这是正确的)。
有没有解决的办法?
提前致谢!
我有从 JSON 创建的 Python 数据类(实际上有很多)。我想要一种从 JSON 创建类实例的方法。
我有这样的事情:
class FromJSONMixin:
@staticmethod
@abstractmethod
def from_json(json: Union[Dict, TypedDict], **kwargs):
raise NotImplementedError
class PatientJSON(TypedDict):
ID: str
Name: str
Description: str
BirthDate: str
@dataclass
class Patient(FromJSONMixin):
name: str
birth_date: str
description: str
@staticmethod
def from_json(json: PatientJSON, **kwargs) -> Patient:
return Patient(
name=json["Name"],
birth_date=json["BirthDate"],
description=raw_data["Description"])
Run Code Online (Sandbox Code Playgroud)
我想Patient从中创建对象PatientJSON(结构与现有数据库相关,我必须与它集成;它还进行一些名称属性翻译,如上所示)。我创建了FromJSONMixin来显式标记可以从 JSON 的相关类创建的类(例如PatientJSON)。
问题:-> Patient:我收到零件错误Unresolved reference 'Patient'。为什么?我无法在同一类的方法中键入类对象?我是否必须放弃输入返回类型?
我尝试在现有字典的第二层实例化一个空字典,然后为其分配一个键值对,但 MyPy 抛出错误。
这是一个最小的示例,当激活 MyPy 检查时它将重现它:
result = {"Test": "something"}
result['key'] = {}
result['key']['sub_key'] = ["some string", "another string"]
Run Code Online (Sandbox Code Playgroud)
这里的错误将类似于:
mypy(error): Incompatible types in assignment (expression has type
"Dict[<nothing>, <nothing>]", target has type "List[str]")
Run Code Online (Sandbox Code Playgroud)
我该如何防止这个错误?根据类似的问题,建议这样做
result['key'] = {} # type: ignore
Run Code Online (Sandbox Code Playgroud)
作为一种解决方法,但这似乎不是很优雅,这就是为什么我想知道是否还有更多的事情可以做。
给出如下内容:
import importlib
module_path = "mod"
mod = importlib.import_module(module_path, package=None)
print(mod.Foo.Bar.x)
Run Code Online (Sandbox Code Playgroud)
哪里mod.py:
class Foo:
class Bar:
x = 1
Run Code Online (Sandbox Code Playgroud)
mypy file.py --strict 引发以下错误:
file.py:7: error: Module has no attribute "Foo" [attr-defined]
Run Code Online (Sandbox Code Playgroud)
我想知道应该如何进行类型提示,或者这是否是通常会被忽略的东西# type: ignore[attr-defined] (假设代码是必要的,并且唯一的选项是类型提示或忽略类型提示)?
importlib在这种情况下使用使用的方式importlib是有一些路径:
x.y.<changes>.z
Run Code Online (Sandbox Code Playgroud)
哪里<changes>是动态的,其他的都是固定的。我确信该模块将包含正在调用的属性,但由于<changes>,importlib用于导入。
可以概括为:
我不确切地知道我将导入哪个模块,但我知道它将有一个
Foo类。
据我所知,以下两种类型在 Python 中是等效的:
Optional[Union[A, B]]
Union[A, B, None]
是否有一个明确的约定可供选择,例如 PEP 中的条款?
from types import ModuleType\nfrom typing import Any, Dict, Tuple, Type, TypeVar\n\nfrom . import default\n\n_T = TypeVar("_T", bound=type)\n\nclass settings_meta(type):\n def __new__(\n cls: Type[_T],\n name: str,\n bases: Tuple[type, ...],\n namespace: Dict[str, Any],\n settings: ModuleType,\n **kwargs: Any,\n ) -> _T:\n from inspect import ismodule\n\n namespace = {\n key: val\n for key, val in vars(settings).items()\n if not key.startswith("__") and not ismodule(val)\n }\n namespace["__annotations__"] = {\n key: val\n for key, val in vars(settings)["__annotations__"].items()\n if key in namespace.keys()\n }\n return type.__new__(cls, name, bases, namespace, **kwargs)\n\n def …Run Code Online (Sandbox Code Playgroud) python type-hinting visual-studio-code python-typing pylance
python ×10
python-typing ×10
type-hinting ×6
mypy ×4
dictionary ×2
python-3.x ×2
annotations ×1
json ×1
liskov-substitution-principle ×1
metaclass ×1
pylance ×1
templates ×1
union-types ×1