【问题标题】:Why do some functions have underscores "__" before and after the function name?为什么有些函数的函数名前后都有下划线“__”?
【发布时间】:2016-02-29 00:59:31
【问题描述】:

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

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

【问题讨论】:

标签: python function methods double-underscore


【解决方案1】:

来自Python PEP 8 -- Style Guide for Python Code

Descriptive: Naming Styles

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

  • _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 本身保留的:“永远不要发明这样的名称;仅按文档说明使用它们”。

【讨论】:

  • Raymond 还解释了为什么您希望在此视频的 34 分钟左右开始进行名称修改行为:youtube.com/watch?v=HTLu2DFOdTg
  • 所以名称中单前导下划线和双前导下划线之间的选择有点像在 C++ 和 Java 中选择保护和私有? _single_leading_underscore 可以被孩子更改,但 __double_leading_underscore 不能?
  • __double_leading_underscore 仍然是公开的,该变量被简单地重命名以避免冲突。
  • 新的重整方法名称,有一个前导下划线,是私有的。例如。 __boo 变为 _FooBar__boo
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    双下划线包围的名称对 Python 来说是“特殊的”。它们在Python Language Reference, section 3, "Data model" 中列出。

    【讨论】:

    • 最后,来自 Google 的快速指针指向 Python 参考手册的右侧部分。谢谢。
    【解决方案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)
        )
    

    ...

    【讨论】:

    • 这不是双下划线前缀的用途吗?
    【解决方案5】:

    添加了一个例子来理解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
    

    【讨论】:

      【解决方案6】:

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

      例如__file__表示Python文件的位置,__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
      

      【讨论】:

        最近更新 更多