如何为python中存在的对象属性(属性)编写接口(契约)?
How to write interface (contract) for object property (attribute) existence in python?
我想就某些函数的参数签订合同,以强制执行参数对象必须具有特定的 属性。我知道 python 不是一种严格类型化的语言,但有时拥有契约和接口非常有用。 Python 现在有类型提示,这很棒,所以我们可以这样做:
def myfunc(myparam: MyType) -> SomeType:
myparam.myprop # this should exist
但是我怎么能说 MyType 必须有一个特定的对象 属性 (myprop) 而无需在 运行 时间内插入断言和抛出异常?
我可以用 abc metaclasses 定义抽象 classes,它可以用作接口。
from abc import ABC, abstractmethod
class MyInterface(ABC):
@property
@abstractmethod
def myprop(self) -> int: pass
现在在代码的某处我可以将 MyType 定义为:
class MyType(MyInterface):
myprop = 8
有效,但是 myprop 是 class 属性 而不是 对象 属性(属性)。我当然可以这样做:
class MyType(MyInterface):
myprop = 0
def __init__(self):
self.myprop = 8
很好,但我必须定义一个(不必要的)class ("static") 属性 并用对象 属性 有效地隐藏它。不是很干净。此外,现在我有一个 myprop 的默认值,这不是我想要的。但如果我这样做:
class MyType(MyInterface):
myprop = None # wrong type here
def __init__(self):
self.myprop = 8
这是错误的,因为 myprop 必须是 int 而不能是 None,它被 linter 正确捕获。应该有一个对象 属性 没有 class 属性。
目标是像 mypy 这样的静态检查器可以捕获 class 不遵守要求参数实例必须具有一些 属性 的已定义接口或合同的实现错误。 =17=]
实现此目的的 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
我正在添加 pycharm 代码检查器警告的图片:
我想就某些函数的参数签订合同,以强制执行参数对象必须具有特定的 属性。我知道 python 不是一种严格类型化的语言,但有时拥有契约和接口非常有用。 Python 现在有类型提示,这很棒,所以我们可以这样做:
def myfunc(myparam: MyType) -> SomeType:
myparam.myprop # this should exist
但是我怎么能说 MyType 必须有一个特定的对象 属性 (myprop) 而无需在 运行 时间内插入断言和抛出异常? 我可以用 abc metaclasses 定义抽象 classes,它可以用作接口。
from abc import ABC, abstractmethod
class MyInterface(ABC):
@property
@abstractmethod
def myprop(self) -> int: pass
现在在代码的某处我可以将 MyType 定义为:
class MyType(MyInterface):
myprop = 8
有效,但是 myprop 是 class 属性 而不是 对象 属性(属性)。我当然可以这样做:
class MyType(MyInterface):
myprop = 0
def __init__(self):
self.myprop = 8
很好,但我必须定义一个(不必要的)class ("static") 属性 并用对象 属性 有效地隐藏它。不是很干净。此外,现在我有一个 myprop 的默认值,这不是我想要的。但如果我这样做:
class MyType(MyInterface):
myprop = None # wrong type here
def __init__(self):
self.myprop = 8
这是错误的,因为 myprop 必须是 int 而不能是 None,它被 linter 正确捕获。应该有一个对象 属性 没有 class 属性。
目标是像 mypy 这样的静态检查器可以捕获 class 不遵守要求参数实例必须具有一些 属性 的已定义接口或合同的实现错误。 =17=]
实现此目的的 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
我正在添加 pycharm 代码检查器警告的图片: