Cody Blog

[Python] Class Private 跟 Module Private 的差別

在Python中雖然有Private variable,但是不像一般程式語言一樣具有強制的效力,如果外界執意要使用還是可以呼叫的到。在這篇StackOverflow有很清楚的解釋其中的差別。

  • Module private 是指是以一個下底線 _ 開頭的變數,例如 _number 或 _getNumber() 

  • Class Private 基本上是以二個下底線 __ 開頭,而且不超過一個下底線 _ 結尾的的變數名稱,例如 __number 或 __getNumber(),但是init 就不是 class private,但這種兩個下底線開頭和結尾叫 Magic methods有其特別的用途,但這個不在本文討論範圍。

Module Private

# moduleA.py

def _foo():
    return 'hi'

from moduleA import *
    print _foo()

以此例子來說,我們在 moduleA.py裡面定義了一個 Module private _foo(),因為Python有個規定是在Import的時侯會略過所有以underscore開頭的成員,所以_foo()會被忽略,在執行 print _foo() 的時侯就會發生 Exception:

Traceback (most recent call last):
File "D:\priavte\__init__.py", line 4, in <module>
NameError: name '_foo' is not defined

但是如果執意要用還是可以透過Import __foo,得到想要的結果

from moduleA  import _foo
print _foo()

Class Private

class Foo():
    __aoo = 123
    def __boo(self):
        return 123
    def coo(self):
        return 456
    f = Foo()

print dir(f)
print f._Foo__boo()
print f.__boo()

可以觀察一下這三個 print 執行的結果,會發現 dir(f)是輸出: > ['_Foo__aoo', '_Foo__boo', '__doc__', '__module__', 'coo'] _boo被加上_Foo_的Prefix,這種行為稱做 Name Mangling,多加上Class Name在前面。所以透過 f.__boo()就沒辦法直接呼叫,但是透過加上Class Name的Prefix就可以了,例如 print f._Foo__boo()

總結

Module private : _number
  1. 達到 Private 的效果:Import 除非明確把 name 打出來,不然 from A import * 時會自動略過所有以一個下底線 _ 開頭的變數
  2. 使用時機:在 Module level 下,告知外界,這些變數/函式是Private性質的,不建議外界直接存取
  3. 強制使用方式: 直接Import即可,例如: from A import _Number
Class Private : __number
  1. 達到 Private 的效果:Class 物件被建立的時侯,所有 __XXX 會被 name mangling成 __ClassName__XXX
  2. 使用時機:跟 Module private 一樣,就是表現出這些成員是內部使用的,不建議外界直接存取
  3. 強制使用方式: 使用的時侯,加上 Class name 的的 prefix
  4. 繼承的時侯,這些被 name mangled 的成員也會被繼承,但是是使用Parent的ClassName的Prefix,要注意一下。 在Python的世界中,Private Variable沒辦法強制讓外界無法使用,透過Naming可以讓別人知道這些Private Variable不應該直接被存取,避免誤用的Bug發生。但是如果執意要呼叫,都還是有方法的。

python

Related Posts

Comments