【问题标题】:How do I annotate a type which has an extra attribute with mypy?如何使用 mypy 注释具有额外属性的类型?
【发布时间】:2021-01-04 07:48:53
【问题描述】:

我有一个ast.UnaryOp 对象,但我手动添加了一个parent 属性(请参阅answer)。如何在函数中对此进行注释?

我目前只有:

def _get_sim206(node: ast.UnaryOp):
    if isinstance(node.parent, ast.If):
        return False
    return True

但是 mypy 抱怨(理所当然地)ast.UnaryOp 没有 parent 属性。

如何告诉 mypy node 不是 ast.UnaryOp 而是 ast.UnaryOp + parent attribute

我的尝试

我创建了自己的 UnaryOp 类,它有一个 parent 属性。我可以将它用于类型转换:

class UnaryOp(ast.UnaryOp):
    def __init__(self, orig: ast.UnaryOp) -> None:
        self.op = orig.op
        self.operand = orig.operand
        self.lineno = orig.lineno
        self.col_offset = orig.col_offset
        self.parent: ast.Expr = orig.parent  # type: ignore

它的缺点是我需要在很多地方进行类型转换,并且我引入了Any。如果我可以在某处声明该文件中的所有ast.* 类型确实具有parent 属性,我会更愿意

【问题讨论】:

    标签: python mypy type-annotation


    【解决方案1】:

    作为一种解决方法,您可以将isinstance() 与带有@runtime_checkable 修饰的protocol 一起使用,这将在运行时检查所有协议成员是否已定义并确保静态正确性。

    from typing import Protocol, runtime_checkable, cast
    import ast
    
    
    @runtime_checkable
    class ParentProto(Protocol):
        parent: ast.AST
        
    
    def foo(node: ast.UnaryOp):
        if isinstance(node, ParentProto):
            # use node.parent
            p = node.parent
            l = node.lineno
    
    # assignment
    g = ast.UnaryOp()
    cast(ParentProto, g).parent = ast.If()
    

    【讨论】:

    • 哦,太好了!我总是忘记protocol
    • 是否可以注释一个参数应该是ast.UnaryOpParentProto? (不是联合,这是类型的逻辑“或”)
    • 据我所知,这是不可能的,与联合相比,mypy 难以表示类型的交集。
    猜你喜欢
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    • 2020-01-24
    • 2016-01-13
    • 1970-01-01
    • 2020-05-05
    相关资源
    最近更新 更多