Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 仅出于文档目的使用抽象基类_Python_Python 3.x_Abstract Class_Code Documentation - Fatal编程技术网

Python 仅出于文档目的使用抽象基类

Python 仅出于文档目的使用抽象基类,python,python-3.x,abstract-class,code-documentation,Python,Python 3.x,Abstract Class,Code Documentation,我有一套类似的类,称为“Executors”,它们在中使用。它们是非常简单的类: class ExecutorA: def execute(self, data): pass class ExecutorB: def execute(self, data): pass 所有执行器的execute()函数都需要以相同的方式运行,即以某种格式获取数据,并以另一种特定格式返回数据。由于duck类型,不需要有基类,所以我没有编写基类 但是,我目前正在使用docstrings等

我有一套类似的类,称为“Executors”,它们在中使用。它们是非常简单的类:

class ExecutorA:
  def execute(self, data):
    pass

class ExecutorB:
  def execute(self, data):
    pass
所有执行器的
execute()
函数都需要以相同的方式运行,即以某种格式获取数据,并以另一种特定格式返回数据。由于duck类型,不需要有基类,所以我没有编写基类

但是,我目前正在使用docstrings等来记录我的代码,我认为最好在抽象基类中记录
execute()
函数的数据格式要求,如下所示:

class Executor(ABC):
  def execute(self, data):
  """Process data in format xy and return data in format zy"""
    pass
我的理由是我不想在每个Executor类中复制相同的文档。这是ABC的常见用例吗

澄清:
我需要使用Python3.6,因为我们正在使用RHEL,新的python尚未正式提供。

如果只是出于文档/静态类型检查的目的,您也可以使用它(从Python3.8开始,通过后端口)。这用于不需要显式继承的对象。所以你可以做:

from typing import List, Protocol

class Executor(Protocol):
    def execute(self, data: List[float]) -> float:  # example type annotations
        """Reduce `data` to a single number."""
        ...

class ExecutorA:  # no base class required, it implements the protocol
    def execute(self, data: List[float]) -> float:
        return sum(data)

def do_work(worker: Executor,  # here we can use the Protocol class
            data: List[float]) -> float:
    return worker.execute(data)

do_work(ExecutorA(), [1., 2., 3.])  # this check passes
这里的文档字符串位于协议类上,提供了
execute
方法的一般信息。由于
Executor
用于类型注释,用户将被引用到协议类。如果需要,还可以向实现中添加附加信息(
ExecutorA
,…),或者复制原始文档字符串(这项工作可以由装饰师完成)


使用抽象基类也是一种解决方案。ABC允许
isinstance
IsubClass
检查,您可以注册不显式继承ABC的其他类。

我认为在Python 3.6中使用抽象基类是一个合理的选择。您可能希望将
execute
修饰为一个,但是\_(ツ)_/''

现在,如果您想对docstring进行更多的控制,您可以创建自己的元类,从中继承。例如,以下是一种“可扩展”docstring的方法,即您的docstring将成为格式字符串,其中
{pdoc}
将始终由(第一个)父类的文档替换(如果存在)

来自abc导入抽象方法,ABCMeta
从检查导入getdoc
DocExtender类(ABCMeta):
定义新(cls、名称、基础、规格):
对于键,规格项()中的值:
doc=getattr(值''.'doc'.''.{pdoc}')
尝试:
pdoc=getdoc(getattr(基[0],键))
除了(索引器错误、属性错误):
pdoc=''
尝试:
值.uuu doc_uuu=doc.format(pdoc=pdoc)
除属性错误外:
通过
返回ABCMeta.\uuuuu新\uuuuuuu(cls、名称、基础、规格)
类ExecutorBase(元类=DocExtender):
@抽象方法
def执行(自我,数据):
"""
父母亲
"""
通过
类别Executor1(ExecutorBase):
def执行(自我,数据):
"""
{pdoc}-Child
"""
返回和(数据)
第2类执行者(执行者库):
def执行(自我,数据):
返回和(数据)
打印(getdoc(Executor1.execute))
#亲子关系
打印(getdoc(Executor2.execute))
#母公司

我发布这篇文章主要是为了说明一般概念;显然,可以根据需要进行调整。

感谢您提供了这个解决方案!但是,我们使用Python3.6,因为我们需要使用RHEL,在RHEL中,更新的python本机还没有提供。@arne将
协议
类后移植到Python3。[5-7]你知道Sphinx是否理解
Protocol
s,是否能够生成有关
execute
函数的适当文档?@arne你的意思是它是否会将实现协议的类链接到协议的文档字符串?我不这么认为,因为即使类执行了对于协议,不能保证您打算从协议基础“派生”此对象。就像类型批注一样,您明确要求类型为
Executor
的对象(因此类型检查器可以确定它们是否兼容),您也需要显式声明任何文档字符串继承。但您可以使用类装饰器从协议类更新文档字符串。在Python中,您实际上不需要类来实现这一点;函数是一级对象,可以作为参数传递,而不需要执行器的实例ss来携带该方法。@chepner这是真的。我的示例简化了很多,事实上,我需要执行器是类,因为它们具有某种状态。虽然我很高兴有机会了解元类,但我以前并不真正了解元类,但仅仅创建文档似乎有点过火。你也可以使用类装饰而是调整函数的文档字符串。@arne amen,+1;-)