Python中什么时候使用下划线命名法?

23
在Python中,有单个下划线、双下划线、双前后下划线和单个尾部下划线的命名约定。许多这些约定在What is the meaning of a single- and a double-underscore before an object name?中的答案中概述。
但是,单个前后下划线的含义或约定是什么?我最初看到它们的使用是在enum模块中:
  • _name_ - 成员的名称
  • _value_ - 成员的值;可以在 new 中设置/修改
  • _missing_ - 当没有找到值时使用的查找函数;可能会被覆盖
  • _ignore_ - 一个名称列表,可以作为 list() 或 str(),它们不会转换为成员,并将从最终类中删除
  • _order_ - 在Python 2/3中用于确保成员顺序一致 (类属性,在创建类时删除)
  • _generate_next_value_ - 由 Functional API 和 auto 使用,以获取枚举成员的适当值;可能会被覆盖

在IT技术中,我之前没见过这种单下划线sunder的命名方式。它们是否有特殊处理或含义,不同于其他下划线相关的命名规范?与没有下划线完全不同的是什么?

1个回答

15

它们没有被特殊对待。枚举模块正在使用它们,以便

  • 不会被意外覆盖

例如:

class Status(Enum):
    alive = auto()
    dead = auto()
    missing = auto()

您可以看到,Status.missingStatus._missing_是不同的对象。如果枚举方法_missing_被命名为missing,我们就会覆盖它。
在Python中,名称_value被视为私有。为了表达这些不是私有的(用户可能希望枚举值是私有的),它们被赋予了下划线名称。_sunder_方法在Enum中像纯Python的__dunder__协议一样起作用,但不被语言保留,其他选择,例如__double_leading_underscore__dunder__等在Python中也具有特殊含义,如上所述。
基本上,这是一种选项,可以避免属性名称冲突,而不会给人留下错误印象。

但是 _name__value_Enum 类型的属性,而不是元类 EnumMeta 的属性。例如 class Test(Enum): a = 0,那么 Test.a._name_ == 'a',但是 Test._name_ 则会引发 AttributeError。我可以理解在 EnumMeta 上需要避免属性名称冲突,但是在生成的 Enum 类型上存在什么冲突风险呢? - gerrit
此外,Test.a.nameTest.a.value 同样 有效,因此似乎 _name__value_ 分别是 namevalue 的同义词。 - gerrit
15
作为 Enum 的作者,我批准这个答案。;-) - Ethan Furman
值得一提的是,流行的Jupyter REPL和可视化框架(包括其强大的IPython)在其增强的REPL环境中广泛使用“sunder”-命名属性和方法,例如_repr_jpeg__repr_html_,以为符合条件的Python对象提供定制渲染(详见https://ipython.readthedocs.io/en/stable/config/integrating.html)。 - fish2000
@gerrit:回答你的问题比我在评论中想要涉及的更加复杂。如果你把它作为一个新问题提出来,我很乐意回答。 - Ethan Furman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接