我对Python中的类型检查非常陌生。我想找到一种方法来使用它检查这种常见情况:
在一个不正确的用法中,我想自动检测:用户实例化db连接器,然后调用query(),而不首先调用connect
是否有带注释的表示?我可以表示connect()方法导致“self”加入一个新类型吗?还是这样做是正确的
是否有其他标准机制用于在Python或mypy中表达并检测它
我也许能看到这是如何用继承来表达的也许。。。我不确定
提前谢谢
编辑:
以下是我希望能做的:
from typing import Union, Optional, NewType, Protocol, cast
class Connector:
def __init__(self, host: str) -> None:
self.host = host
def run(self, sql: str) -> str:
return f"I ran {sql} on {self.host}"
# This is a version of class 'A' where conn is None and you can't call query()
class NoQuery(Protocol):
conn: None
# This is a version of class 'A' where conn is initialized. You can query, but you cant call connect()
class CanQuery(Protocol):
conn: Connector
# This class starts its life as a NoQuery. Should switch personality when connect() is called
class A(NoQuery):
def __init__(self) -> None:
self.conn = None
def query(self: CanQuery, sql: str) -> str:
return self.conn.run(sql)
def connect(self: NoQuery, host: str):
# Attempting to change from 'NoQuery' to 'CanQuery' like this
# mypy complains: Incompatible types in assignment (expression has type "CanQuery", variable has type "NoQuery")
self = cast(CanQuery, self)
self.conn = Connector(host)
a = A()
a.connect('host.domain')
print(a.query('SELECT field FROM table'))
b = A()
# mypy should help me spot this. I'm trying to query an unconnected host. self.conn is None
print(b.query('SELECT oops'))
对我来说,这是一个常见的场景(一个具有一些不同且非常有意义的操作模式的对象)。没有办法用mypy来表达这一点吗
通过使用文字枚举将
A
类设置为泛型类型,(ab)并注释self参数,您可能可以将一些东西组合在一起,但坦率地说,我认为这不是一个好主意Mypy通常假设调用一个方法不会改变方法的类型,如果不借助大量的hacks和强制转换或
# type: ignore
,就不可能避免这种情况相反,标准约定是使用两个类“连接”对象和“查询”对象以及上下文管理器。作为一个附带的好处,这还可以让您确保在使用完连接后始终关闭连接
例如:
如果您真的想将这两个新类合并为一个类,您可以通过(ab)使用文字类型、泛型和自注释,并保持在只能返回具有新特性的实例的约束范围内
例如:
基本上,只要我们坚持使用返回新实例(即使在运行时,我们总是只返回“self”),就可以使类型或多或少地充当状态机
再聪明一点/再折衷一点,你甚至可以在从一个州过渡到另一个州的时候摆脱演员阵容
但是我认为这类把戏对你似乎要做的事情来说是过分的/不合适的。我个人推荐两个类+contextmanager方法相关问题 更多 >
编程相关推荐