何时使用 Python Ellipsis 优于“pass”?

sam*_*ise 18 python

当我找到abc模块(https://docs.python.org/3/library/abc.html)时,我只是在寻找在 Python 中定义抽象基类的方法。

经过一番阅读,我看到了以下课程:

class C(ABC):
    @abstractmethod
    def my_abstract_method(self, ...):
        ...
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, ...):
        ...
Run Code Online (Sandbox Code Playgroud)

想知道三个点,我发现它被称为Ellipsis( https://docs.python.org/3/library/constants.html#Ellipsis )。到目前为止,我只在结合类型提示的情况下看到并使用过它,在这种情况下它非常有意义。

但是为什么要在抽象方法的定义中使用省略号呢?就个人而言,我要么做

def my_abstract_method(self):
    raise RuntimeError("NotImplemented")
Run Code Online (Sandbox Code Playgroud)

或者

def my_abstract_method(self):
    pass
Run Code Online (Sandbox Code Playgroud)

那么为什么pass官方文档中更喜欢省略号呢?它只是自以为是吗?

小智 32

由于抽象类的工作原理,我几乎只在抽象类中使用省略号。

对我来说,pass意味着“什么都不做”或“NOOP”,但...意味着“细节在其他地方定义”。

抽象方法实际上不能被重写。现在,从技术上讲,您可以调用super().abstractmeth()并运行在 Abstractmethod 定义中定义的代码,但我使用的常用模式是在此处使用省略号来指示在阅读时应在其他地方完全重新定义该方法的内容。

如果你只是放一个,pass有人可能会认为这是一个稍后要填写的存根方法,但省略号通常会让人们意识到发生了一些不同的事情。


Daw*_*weo 19

我查看了python(3.7)文档并

\n
pydoc ...\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see Slicings).  It supports\nno special operations.  There is exactly one ellipsis object, named\n"Ellipsis" (a built-in name).  "type(Ellipsis)()" produces the\n"Ellipsis" singleton.\n\nIt is written as "Ellipsis" or "...".\n\nRelated help topics: SLICINGS\n
Run Code Online (Sandbox Code Playgroud)\n

\n
pydoc pass\nThe "pass" statement\n********************\n\n   pass_stmt ::= "pass"\n\n"pass" is a null operation \xc5\x9a when it is executed, nothing happens. It\nis useful as a placeholder when a statement is required syntactically,\nbut no code needs to be executed, for example:\n\n   def f(arg): pass    # a function that does nothing (yet)\n\n   class C: pass       # a class with no methods (yet)\n
Run Code Online (Sandbox Code Playgroud)\n

所以至少从pydoc角度来看,这似乎pass是定义不执行任何操作的函数的方法。

\n


Blc*_*ght 15

使用Ellipsis文字作为函数体什么都不做。如果您使用它而不是pass其他语句,这纯粹是风格问题。如果你给你的函数一个文档字符串,你甚至不需要在带有文档字符串的行之后放置任何语句。

如果官方 Python 文档不一致,可能是因为编写文档的 Python 核心开发人员自己对哪个看起来最好没有一致的意见。PEP 8 没有给出任何关于如何用于虚拟函数体的建议(尽管它确实使用了很多...s 来代表其示例中的事物,有时在您实际上无法Ellipsis在实际代码中使用的地方)。

因此,对于您自己的代码,请使用您最喜欢的任何内容。如果你想正式一点,在你的风格指南中写下你的偏好,然后总是按照指南说的去做。你并不需要遵循相同的风格别人(除非那个人是你的老板)。

最后一个注意事项:您不能...在函数定义中用作参数名称(无论下一行是什么,都会def my_abstract_method(self, ...):引发 a SyntaxError)。

  • `...` 不是惯用语。 (4认同)
  • @MartinThoma 我不知道有任何开发人员对此发表评论,但我也没有去寻找。我怀疑文档中的“...”符号最初是一个文本内容,标记了额外的内容可以去的地方,但为了简洁而省略了它。但由于文字在某些地方*是*有效的代码,因此有时会被实际使用。 (3认同)
  • 有一些协议建议在存根中使用“...”:https://github.com/python/typing/issues/109 但不确定它的采用范围有多大。 (3认同)

Jon*_*tes 5

我同意@Blckknght 和@noharmpun。生成的字节码几乎相同。

In [13]: dis.dis("def B(): ...; B()")


  1           0 LOAD_CONST               0 (<code object B at 0x111bf6130, file "<dis>", line 1>)
              2 LOAD_CONST               1 ('B')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (B)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE

Disassembly of <code object B at 0x111bf6130, file "<dis>", line 1>:
  1           0 LOAD_GLOBAL              0 (B)
              2 CALL_FUNCTION            0
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
In [14]: dis.dis("def A(): pass; A()")


  1           0 LOAD_CONST               0 (<code object A at 0x111bf59a0, file "<dis>", line 1>)
              2 LOAD_CONST               1 ('A')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (A)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE

Disassembly of <code object A at 0x111bf59a0, file "<dis>", line 1>:
  1           0 LOAD_GLOBAL              0 (A)
              2 CALL_FUNCTION            0
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE

Run Code Online (Sandbox Code Playgroud)