为什么有些函数在函数名称前后都有下划线“__”?

Why do some functions have underscores "__" before and after the function name?

提问人:Chuck Testa 提问时间:1/1/2012 最后编辑:ZF007Chuck Testa 更新时间:1/17/2023 访问量:404893

问:

这种“下划线”似乎经常发生,我想知道这是 Python 语言的要求,还是仅仅是约定俗成的问题?

另外,有人可以说出并解释哪些函数往往带有下划线,以及为什么(例如)?__init__

python 函数 方法 双下划线

评论

9赞 1/1/2012
@AustinHenley:不适用于名称前后的双下划线。您只考虑在名称之前添加下划线。
2赞 David Cary 9/20/2016
相关:“Python 对 Class Private 成员使用双下划线的历史原因是什么?
4赞 MackM 4/13/2017
对象名称前的单下划线和双下划线的可能副本是什么?
1赞 Georgy 5/28/2020
@MackM 请注意,此问题询问名称前后的下划线,而您建议的重复目标仅在名称之前询问下划线。不过,我承认那里的一些答案也涵盖了这种情况。

答:

778赞 Michael Burr 1/1/2012 #1

摘自 Python PEP 8 -- Python 代码风格指南

描述性:命名样式

以下使用前导或尾随下划线的特殊形式是 公认的(这些通常可以与任何案例约定结合使用):

  • _single_leading_underscore:弱的“内部使用”指标。例如 不导入名称以下划线开头的对象。from M import *

  • single_trailing_underscore_:约定使用以避免与 Python 关键字冲突,例如

    Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore:在命名类属性时,调用名称篡改(在类 FooBar 中,变为;见下文)。__boo_FooBar__boo

  • __double_leading_and_trailing_underscore__:位于用户控制的命名空间中的“魔术”对象或属性。例如,或 。永远不要发明这样的名字;仅按文档使用它们。__init____import____file__

请注意,带有双前导和尾随下划线的名称基本上是为 Python 本身保留的:“永远不要发明这样的名称;仅按文件使用它们”。

评论

13赞 johncip 5/26/2014
Raymond 还解释了为什么你希望从这个视频的 34 分钟左右开始出现名字篡改行为: youtube.com/watch?v=HTLu2DFOdTg
8赞 Alex W 6/5/2014
因此,在名称中的单前导下划线和双前导下划线之间进行选择有点像在 C++ 和 Java 中在受保护和私有之间进行选择?_single_leading_underscore可以被孩子改变,但__double_leading_underscore不能?
4赞 c z 9/21/2017
__double_leading_underscore仍然是公共的,变量只是重命名以避免冲突。
1赞 hi2meuk 8/7/2021
新的修改方法名称(具有单个前导下划线)是私有的。例如 成为__boo_FooBar__boo
0赞 Ben Slade 11/24/2022
说到“双前导和尾随下划线”部分的答案,这里的“魔术”是什么意思?当您说“按文档使用它们”时,我使用它们是为了什么?你的意思是,“这些是 python 要调用的方法,而不是你”?
32赞 Ignacio Vazquez-Abrams 1/1/2012 #2

用双下划线括起来的名称对 Python 来说是“特殊的”。它们在 Python 语言参考的第 3 节“数据模型”中列出。

评论

3赞 MrBrody 8/11/2021
最后,来自 Google 的快速指针指向 Python 参考手册的右侧部分。谢谢。
86赞 Raymond Hettinger 1/1/2012 #3

其他受访者将双前导和尾随下划线描述为“特殊”或“魔术”方法的命名约定是正确的。

虽然您可以直接调用这些方法(例如),但下划线的存在暗示这些方法旨在间接调用(例如)。大多数python运算符都有一个相关的“魔术”方法(例如,是调用的常用方式)。[10, 20].__len__()len([10, 20])a[x]a.__getitem__(x)

7赞 Omadbek Onorov 8/31/2015 #4

实际上,当我需要区分父类和子类名时,我使用 _ 方法名称。我读过一些使用这种方式创建父子类的代码。作为一个例子,我可以提供以下代码:

class ThreadableMixin:
   def start_worker(self):
       threading.Thread(target=self.worker).start()

   def worker(self):
      try:
        self._worker()
    except tornado.web.HTTPError, e:
        self.set_status(e.status_code)
    except:
        logging.error("_worker problem", exc_info=True)
        self.set_status(500)
    tornado.ioloop.IOLoop.instance().add_callback(self.async_callback(self.results))

...

和有_worker方法的孩子

class Handler(tornado.web.RequestHandler, ThreadableMixin):
   def _worker(self):
      self.res = self.render_string("template.html",
        title = _("Title"),
        data = self.application.db.query("select ... where object_id=%s", self.object_id)
    )

...

评论

1赞 AMC 2/12/2020
这不就是双下划线前缀的用途吗?
5赞 Shagun Pruthi 1/18/2019 #5

此约定用于特殊变量或方法(所谓的“魔术方法”),例如 和 。这些方法提供特殊的句法特征或执行特殊的事情。__init____len__

例如,表示 Python 文件的位置,在执行表达式时执行。__file____eq__a == b

当然,用户可以创建一个自定义的特殊方法,这是一个非常罕见的情况,但通常可能会修改一些内置的特殊方法(例如,你应该初始化类,当它创建一个类的实例时,它将首先执行)。__init__

class A:
    def __init__(self, a):  # use special method '__init__' for initializing
        self.a = a
    def __custom__(self):  # custom special method. you might almost do not use it
        pass
11赞 Hitesh Sahu 1/28/2020 #6

添加了一个示例来了解 python 中 __ 的用法。这是所有 __ 的列表

https://docs.python.org/3/genindex-all.html#_

某些类别的标识符(关键字除外)具有特殊的 意义。在任何其他上下文中,对 * 名称的任何使用,但不会 遵循明确记录的使用,否则会破损 警告

使用 __ 的访问限制

"""
Identifiers:
-  Contain only (A-z, 0-9, and _ )
-  Start with a lowercase letter or _.
-  Single leading _ :  private
-  Double leading __ :  strong private
-  Start & End  __ : Language defined Special Name of Object/ Method
-  Class names start with an uppercase letter.
-

"""


class BankAccount(object):
    def __init__(self, name, money, password):
        self.name = name            # Public
        self._money = money         # Private : Package Level
        self.__password = password  # Super Private

    def earn_money(self, amount):
        self._money += amount
        print("Salary Received: ", amount, " Updated Balance is: ", self._money)

    def withdraw_money(self, amount):
        self._money -= amount
        print("Money Withdraw: ", amount, " Updated Balance is: ", self._money)

    def show_balance(self):
        print(" Current Balance is: ", self._money)


account = BankAccount("Hitesh", 1000, "PWD")  # Object Initalization

# Method Call
account.earn_money(100)

# Show Balance
print(account.show_balance())

print("PUBLIC ACCESS:", account.name)  # Public Access

# account._money is accessible because it is only hidden by convention
print("PROTECTED ACCESS:", account._money)  # Protected Access

# account.__password will throw error but account._BankAccount__password will not
# because __password is super private
print("PRIVATE ACCESS:", account._BankAccount__password)

# Method Call
account.withdraw_money(200)

# Show Balance
print(account.show_balance())

# account._money is accessible because it is only hidden by convention
print(account._money)  # Protected Access

评论

2赞 hlongmore 5/21/2022
有没有一个地方记录了 lead as 的用法?我没有在链接的文档中看到它,也没有在该文档中指向 __ 标识符的链接下看到它。那里记录了单个前导下划线;使用名称篡改的类私有名称的双前导下划线记录在那里;但似乎称“超级私有”具有误导性,并可能导致人们在文件级函数上使用它,据我所知,它实际上没有任何意义。__strong private__
1赞 Shakhrul Iman Siam 1/17/2023 #7

在 Python 中,在函数名称中使用下划线表示该函数仅供内部使用,不应由用户直接调用。它是一种约定,用于指示该函数是“私有的”,而不是模块的公共 API 的一部分。但是,它不会由语言强制执行,如果用户选择这样做,仍然可以由用户调用。