R H*_*ill 5 python type-hinting abstract-algebra finite-group-theory mypy
这是一个由两部分组成的问题,但第二部分依赖于第一部分。
出于教育目的,我试图为组实现一个抽象基类和测试套件(抽象代数的概念)。代数群定义的一部分相当于类型约束,我想在 ABC 上实现该类型约束,并且如果具体类上的方法不符合该约束,则会有一些抱怨。
我已经为逻辑下的布尔值组实现了第一遍实现and,但它至少有两个问题,我希望你能帮助我修复它。
from __future__ import annotations
from abc import ABC, abstractmethod
class AbsGroup(ABC):
@abstractmethod
def op(self, other: AbsGroup) -> AbsGroup: # <-- Line-of-interest #1
pass
class Bool(AbsGroup):
def __init__(self, val="False"):
if val not in ["True", "False"]:
raise ValueError("Invalid Bool value %s" % val)
self.val = val
def op(self, other):
"""Logical AND"""
if self.val == "True" and other.val == "True": # <-- Line-of-interest #2
return Bool("True")
return Bool("False")
def __eq__(self, other):
return self.val == other.val
def __repr__(self):
return self.val
Run Code Online (Sandbox Code Playgroud)
首先:兴趣线#1 正在执行类型约束工作,但当前的实现是错误的。它仅检查该方法是否接收并返回一个AbsGroup实例。这可以是任何AbsGroup实例。我希望它检查它所继承的具体类,它接收并返回该具体类的实例(因此在Bool它接收并返回 的实例的情况下Bool)。练习的重点是在一个位置执行此操作,而不是必须在每个具体类上专门设置它。我认为这是通过一些类型提示泛型完成的,这些泛型比我尚未深入研究的类型提示更深一些。我该怎么做呢?
其次:如何检查具体方法是否符合抽象类型提示?我的 IDE (PyCharm) 中的类型检查器抱怨 Line-of-interest #2,因为它期望other类型为AbsGroup,而该类型没有属性val。这是预料之中的,如果我能找到第一个问题的解决方案,这种情况就会消失,但我的 IDE 是我能找到的唯一注意到这种差异的东西。mypy默认情况下对此事保持沉默,flake8 和 pylint 也是如此。PyCharm 的功能很棒,但如果我想将其合并到工作流程中,我必须运行什么命令,如果我的具体方法不符合抽象签名,该命令会失败?
第一个提示:如果mypy告诉你的还不够,请尝试mypy --strict。
您正确地认识到基类中的类型注释op限制不够,实际上与子类不兼容。
看看这个不起作用的例子。
from __future__ import annotations
from abc import ABC, abstractmethod
class AbsGroup(ABC):
@abstractmethod
def op(self, other: AbsGroup) -> AbsGroup:
pass
class Bool(AbsGroup):
def __init__(self, val: str = "False") -> None:
self.val = val
def op(self, other: Bool) -> Bool:
...
Run Code Online (Sandbox Code Playgroud)
我用正确的类型注释op了,但现在 mypy 抱怨:Bool
file.py:15: 错误:“op”的参数 1 与超类型“AbsGroup”不兼容;超类型将参数类型定义为“AbsGroup”
您有两个选择:要么使基本注释的限制更少(Any),要么使您的类成为Generic一个:
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TypeVar, Generic
T = TypeVar('T')
class AbsGroup(Generic[T], ABC):
@abstractmethod
def op(self, other: T) -> T:
pass
# EDIT: ADDED QUOTES AROUND Bool
class Bool(AbsGroup['Bool']):
def __init__(self, val: str = "False") -> None:
self.val = val
def op(self, other: Bool) -> Bool:
...
Run Code Online (Sandbox Code Playgroud)
这涉及几个步骤:
T(看起来类似于其他语言中的泛型类型变量)Generic[T]使其成为泛型类op方法以获取并返回TAbsGroup[Bool](在 C++ 中这称为CRTP)这会沉默mypy --strict,PyCharm 会正确推断 的返回类型op。
编辑:
之前的子类定义看起来像这样,class Bool(AbsGroup[Bool]): ... 没有引号。但这不起作用,并且会NameError在创建类时抛出:
NameError:名称“Bool”未定义
这是PEP 563中所写的预期行为。
[...] 但是,打字模块中的一些 API 使用该语言的其他语法结构,并且这些 API 仍然需要使用字符串文字解决前向引用问题。该列表包括:[...]
基类:
class C(Tuple['<type>', '<type>']): ...
因此,即使我们使用了 future 导入,在这种情况下仍然需要引号。
请注意:为什么使用字符串符号作为布尔值?已经有两个完美工作的实例,称为True和False。这将使您的代码更加简单。例如,构造函数中的检查可以简化为if type(val) is bool(我不会isinstance在这里使用,因为您可能不想val成为自定义类型?)。
| 归档时间: |
|
| 查看次数: |
3014 次 |
| 最近记录: |