Python – _ (底線) 與 _ _(雙底線)

第一次看到 Python 的 Code 時候發現寫法使用很多 _ (底線) 與 _ _(雙底線),原來是有其建議規定的. 參考文章 – https://medium.com/bits-to-blocks/python%E4%B8%AD%E7%9A%84underscore-%E8%88%87-9b40caf32483

關於 _single_leading_underscore , single_trailing_underscore_ , __double_leading_underscore 與 __double_leading_and_trailing_underscore__ 的定義在 – https://peps.python.org/pep-0008/

  • _single_leading_underscore

    weak “internal use” indicator. E.g. from M import * does not import objects whose names start with an underscore.

    使用在 Class 時 from Module_Name import * 將不導入名稱有_ (底線)的函數.

    [root@localhost ~]# vi underscore_fun.py
    def add_data(data1 , data2):
        return data1+data2
    
    def _sub_data(data1 , data2):
        return data1-data2
    
    [root@localhost ~]# vi underscore4.py
    from underscore_fun import *
    
    print(add_data(2,3))
    print(_sub_data(2,3))
    

    執行結果, 可以發現 _sub_data 並沒有被匯入.

    [root@localhost ~]# python3 underscore4.py
    5
    Traceback (most recent call last):
      File "underscore4.py", line 4, in <module>
        print(_sub_data(2,3))
    NameError: name '_sub_data' is not defined
    

    如要強制匯入需指定.

    [root@localhost ~]# vi underscore5.py
    from underscore_fun import add_data , _sub_data
    
    print(add_data(2,3))
    print(_sub_data(2,3))
    

    執行結果

    [root@localhost ~]# python3 underscore5.py
    5
    -1
    

    或是在 Module 裡面加入 __all__ 即可成功import

    [root@localhost ~]# vi underscore_fun.py
    def add_data(data1 , data2):
        return data1+data2
    
    def _sub_data(data1 , data2):
        return data1-data2
    
    __all__ = ['add_data', '_sub_data']
    
    [root@localhost ~]# vi underscore4.py
    from underscore_fun import *
    
    print(add_data(2,3))
    print(_sub_data(2,3))
    

    執行結果

    [root@localhost ~]# python3 underscore4.py
    5
    -1
    
  • single_trailing_underscore_

    used by convention to avoid conflicts with Python keyword, e.g. tkinter.Toplevel(master, class_=’ClassName’)

    我們的命名可以使用 name_ 來避免跟 Python 的關鍵字衝突.

    以下是 python keyword 列表.

    [root@localhost ~]# python3
    Python 3.6.8 (default, Mar 25 2022, 11:15:52) 
    [GCC 8.5.0 20210514 (Red Hat 8.5.0-10)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import keyword
    >>> print(keyword.kwlist)
    ['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
    
  • __double_leading_underscore

    when naming a class attribute, invokes name mangling.

    1. 使用在 Class 屬性 (Attribute) 使用 __attribute 這種命名規則時是不希望它被直接被存取.
      [root@localhost ~]# vi underscore2.py
      class data:
          def __init__(self, data1 , data2 ):
              self.data1 = data1
              self.__data2 = data2
      
      a = data(1,2)
      print(a.data1)
      print(a.__data2)
      

      執行結果

      [root@localhost ~]# python3 underscore2.py
      1
      Traceback (most recent call last):
        File "underscore2.py", line 8, in <module>
          print(a.__data2)
      AttributeError: 'data' object has no attribute '__data2'
      

      __attribute 還是可以透過 _類別名稱+屬性名稱 的方式來存取.不建議這麼做,最好不要讓外界知道其存在.

      print(a._data__data2)
      

      正規要存取 __attribute 需透過 @Property 包含 setter , getter 與 deleter 等方法 (Method) 來存取 – https://benjr.tw/104268

    2. 避免 Class 子類別繼承時所發生的名稱衝突(name clashes).
      父子類別皆使用到 data 這個名稱的屬性.

      [root@localhost ~]# vi underscore3.py
      class C1:
        data = 10
        def get_data(self):
         return self.data
      
      class C2(C1):
        def add_data(self,num):
         self.data = 2
         return self.get_data() + num
      
      cdata = C2()
      print(cdata.add_data(5))
      print(cdata.data)
      

      執行結果, 可以看到輸出 是 2 (使用到 C2 的 data 值)+5=7

      [root@localhost ~]# python3 underscore3.py
      7
      2
      

      為避免 Class 子類別繼承時所發生的名稱衝突(name clashes),父類別屬性使用 __attribute .下面範例 C1 類別 data 屬性使用 __data 來取代.

      [root@localhost ~]# vi underscore3.py
      class C1:
        __data = 10
        def get_data(self):
         return self.__data
      
      class C2(C1):
        def add_data(self,num):
         self.data = 2
         return self.get_data() + num
      
      cdata = C2()
      print(cdata.add_data(5))
      print(cdata.data)
      

      執行結果, 可以看到輸出 是 10 (使用到 C1 的 data 值)+5=15

      [root@localhost ~]# python3 underscore3.py
      15
      2
      
  • __double_leading_and_trailing_underscore__

    “magic” objects or attributes that live in user-controlled namespaces. E.g. __init__, __import__ or __file__. Never invent such names; only use them as documented.
    這是些 python 自身定義好使用雙底線的關鍵字.常見的如 __init__ , __new__ , __file__ , __eq__ 等…

沒有解決問題,試試搜尋本站其他內容

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料