Python從設計之初就是一門面向對象的語言,面向對象思想的第一個要素就是封裝。所謂封裝,通俗的講就是類中的屬性和方法,分為公有和私有,公有可以被外界訪問,私有不能被外界訪問,這就是封裝中最關鍵的概念——訪問控制。本文和大家分享的就是訪問控制相關內容,一起來看看吧,希望對想學習python的童鞋有所幫助。
訪問控制有三種級別:私有、受保護、公有
私有(Private):只有類自身可以訪問 受保護(Protected):只有類自身和子類可以訪問 公有(Public):任何類都可以訪問
由于Python不像Java,有訪問控制符(private / public / protected),所以Python的訪問控制也是容易被應聘者忽視和搞錯的。
公有(Public)
在Python的類中,默認情況下定義的屬性都是公有的。
class Foo(object):
bar = 123
def __init__(self, bob):
self.bob = bob
print(Foo.bar) # 123
foo = Foo(456)
print(foo.bob) # 456
上面類 Foo 中的 bar 屬性就是類屬性, __init__ 方法中定義的bob是實例屬性, bar 和bob 都是公有的屬性,外部可以訪問,分別print類中的 bar 和實例中的 bob ,輸出了對應的值。
受保護(Protected)
在Python中定義一個受保護的屬性,只需要在其名字前加一個下劃線 _ ,我們將Foo方法中的bob 和 bar 改為 _bob 和 _bar ,他們就變成了受保護的屬性了,代碼如下:
class Foo(object):
_bar = 123
def __init__(self, bob):
self._bob = bob
class Son(Foo):
def print_bob(self):
print(self._bob)
@classmethod
def print_bar(cls):
print(cls._bar)
Son.print_bar() # 123
son = Son(456)
son.print_bob() # 456
定義一個類 Son 繼承自 Foo ,由于受保護的對象只能在類的內部和子類中被訪問,不能直接調用 print(Son._bar) 或 print(son._bob) 來輸出這兩個屬性的值,所以定義了 print_bar 和 print_bob 方法,實現在子類中輸出,這段代碼也正常的輸出了 _bar 和 _bob 的值。
接下來,試著反向驗證一下,在類的外部,能不能訪問其屬性,將上面代碼的輸出部分修改如下:
print(Son._bar) # 123
son = Son(456)
print(son._bob) # 456
(假裝)驚訝的發(fā)現,竟然沒有報錯,也輸出了正確的值。
Python中用加下劃線來定義受保護變量,是一種約定的規(guī)范,而不是語言層面真的實現了訪問控制,所以,我們定義的保護變量,依然可以在外部被訪問到(這是個feature,不是bug)。
私有(private)
Python定義私有屬性,需要在屬性名前加兩個下劃線 __ ,把上面的代碼修改一下,運行一下會發(fā)現下面的代碼中的任何一個print都會報錯的。
class Foo(object):
__bar = 123
def __init__(self, bob):
self.__bob = bob
class Son(Foo):
def print_bob(self):
print(self.__bob) # Error
@classmethod
def print_bar(cls):
print(cls.__bar) # Error
print(Son.__bar) # Error
son = Son(456)
print(son._bob) # Error
深入一下——私有屬性真的就訪問不到了嗎?
要了解私有屬性是否真的訪問不到,需要從Python是如何實現私有屬性入手。CPython中,會把雙下劃線的屬性變?yōu)?nbsp;_ClassName__PropertyName 的形式,用代碼演示一下:
class Foo(object):
__bar = 123
print(Foo._Foo__bar) # 123
運行一下可以知道,正常輸出了 __bar 的值,但是不推薦這樣去訪問私有屬性,因為不同的Python解釋器對于私有屬性的處理不一樣。
特例
使用雙下劃線定義私有屬性,有一種特殊情況,當屬性后也有兩個下劃線的時候,這個屬性會被Python解釋器當做魔術方法,從而不做私有處理。
class Foo(object):
__bar__ = 123
print(Foo.__bar__) # 123
上面代碼輸出了123,證明Python解釋器并沒有把 __bar__ 當做私有屬性。當定義私有屬性時,需要注意名字最后最多只能有一個下劃線。
另一個特例
假如定義的屬性名就叫 __ 呢?不妨直接試一下:
class Foo(object):
__ = 123
print(Foo.__) # 123
可以發(fā)現名字叫 __ 的屬性也不會被認為是私有屬性,名字是多個下劃線的屬性也不是私有屬性(比如 _______ )。
來源:網絡