如何使用静态检查来确保对象具有特定的方法/属性?

问题描述

我是否可以对函数进行注释,以确保传递给函数的对象具有特定的方法属性,但是我不在乎其实际类型?

Pycharm在内部使用类似于{b}的语法来表示该对象需要哪些推断的方法/属性,但这似乎不是有效的Python语法

def func(a: {b}):  # Error
    a.b = 1

有没有一种方法可以让类型检查器协助鸭子输入,我只在乎对象具有什么方法/属性,而不在乎对象的类型,而不能修改想要的类型检查吗?

解决方法

Protocols可以使用。我将其记录在这里,因为我发现这是一个很难找到的主题。尤其是检查属性是否存在。

为了确保属性的存在:

from typing import Protocol

class HasFoo(Protocol):     # Define what's required
    foo: int

class Foo:                  # This class fulfills the protocol implicitly
    def __init__(self):
        self.foo = 1

class Bar:
    def __init__(self):     # This class fails to implicitly fulfill the protocol
        self.bar = 2

def foo_func(f: HasFoo):
    pass

foo_func(Foo())             # Type check succeeds
foo_func(Bar())             # Type check fails

请注意foo之后的类型提示。要求该行在语法上有效,并且该类型必须与所检查属性的推断类型匹配。如果您关心typing.Any的存在而不是其类型,那么foo可以用作占位符。


类似地,检查方法也可以这样做:

class HasFoo(Protocol):
    def foo(self):
        pass

class Foo:
    def foo(self):
        pass
    
class Bar:
    def bar(self):
        pass

def func(f: HasFoo):
    pass

func(Foo())             # Succeeds
func(Bar())             # Fails

类型检查是通过Pycharm 2020.2.2完成的。