如何编写python中对象属性(属性)存在的接口(合约)?

got*_*uru 5 python abstract-class interface contract python-3.x

我想对某个函数的参数签定合同,以强制参数对象必须具有特定的属性。我了解python不是严格类型的语言,但是有时具有合同和接口非常有用。Python现在具有类型提示,这很好,因此我们可以这样做:

def myfunc(myparam: MyType) -> SomeType:
    myparam.myprop # this should exist
Run Code Online (Sandbox Code Playgroud)

但是,如何说MyType必须具有特定的对象属性(myprop),而又不能在运行时插入断言和引发异常?我可以用abc元类定义抽象类,该类可以用作接口。

from abc import ABC, abstractmethod
class MyInterface(ABC):
     @property
     @abstractmethod
     def myprop(self) -> int: pass
Run Code Online (Sandbox Code Playgroud)

现在在代码中的某个地方,我可以将MyType定义为:

class MyType(MyInterface):
    myprop = 8
Run Code Online (Sandbox Code Playgroud)

它正在工作,但是 myprop是类属性,而不是对象属性(属性)。我当然可以这样做:

class MyType(MyInterface):
    myprop = 0
    def __init__(self):
        self.myprop = 8
Run Code Online (Sandbox Code Playgroud)

很好,但是我必须定义一个(不必要的)类(“静态”)属性,并使用对象属性有效地将其隐藏。不太干净。而且现在我有一个myprop的默认值,这不是我想要的。但是,如果我这样做:

class MyType(MyInterface):
    myprop = None  # wrong type here
    def __init__(self):
        self.myprop = 8
Run Code Online (Sandbox Code Playgroud)

这是错误的,因为myprop 必须为 int且不能为None,这是由linter 正确捕获的。应该有一个没有类属性的对象属性。

目标是像mypy这样的静态检查器可以捕获实现错误,其中类不遵循已定义的接口或协定,而该协定或协定要求参数实例必须具有某些属性。

什么是pythonic(或不是pythonic)的实现方式?

Pet*_*cka 2

您不需要创建新的接口或实现ABC。您可以使用@dataclass。我在 pycharm 中使用默认代码检查器(警告在注释中)。

from dataclasses import dataclass


@dataclass
class MyType:
    my_prop: int


@dataclass
class SomeType:
    my_prop_out: int


def my_func_ok(my_param: MyType) -> SomeType:
    some_type = SomeType(my_prop_out=my_param.my_prop)
    return some_type


def my_func_bad(my_param: MyType) -> SomeType:
    return my_param              # this is not returning SomeType


my_type = MyType()               # this is expecting to set my_prop
my_type = MyType(my_prop="sss")  # this is expecting to set my_prop with int not str
my_func_ok(my_param=100)         # this is expecting MyType object

my_func_ok(my_param=MyType(my_prop=10))  # this is correct, no errors
Run Code Online (Sandbox Code Playgroud)

我正在添加 pycharm 代码检查器警告的图片:


在此输入图像描述