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)的实现方式?
您不需要创建新的接口或实现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 代码检查器警告的图片: