天天看點

Python面向對象程式設計-通路限制

在Class内部,可以有屬性和方法,而外部代碼可以通過直接調用執行個體變量的方法來操作資料,這樣,就隐藏了内部的複雜邏輯。但是,從前面Student類的定義來看,外部代碼還是可以自由地修改一個執行個體的

name

score

屬性:

>>> bart = Student('Bart Simpson', 59)
>>> bart.score
59
>>> bart.score = 99
>>> bart.score
99
           

如果要讓内部屬性不被外部通路,可以把屬性的名稱前面加上兩個下劃線

__

, 在Python中,執行個體的變量名如果以

__

開頭,就變成了一個私有變量(private),隻有内部可以通路,外部不能通路,是以,我們把Student類改一改:

class Student(object):
    def __init__(self, name, score):
          self.__name = name
          self.__score = score

    def print_score(self):
          print('%s: %s' % (self.__name, self.__score))
           

改完後,對于外部代碼來說,沒有什麼改動,但是已經無法從外部通路

執行個體變量.__name

執行個體變量.__score

了:

>>> bart = Student('Bart Simpson', 59)
>>> bart.__name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'
           

這樣就確定了外部代碼不能随意修改對象内部的狀态,這樣通過通路限制的保護,代碼更加健壯。

但是如果外部代碼要擷取name 和score怎麼辦?可以給Student類增加

get_name

get_score

這樣的方法:

class Student(object):
    ...
  def get_name(self):
        return self.__name
 def get_score(self):
        return self.__score
           

如果又要允許外部代碼修改score怎麼辦?可以再給Student類增加

set_score

方法:

class Student(object):
    ...
    def set_score(self, score):
          self.__score = score
           

你也許會問,原先那種直接通過

bart.score = 99

也可以修改啊,為什麼要定義一個方法大費周折?因為在方法中,可以對參數做檢查,避免傳入無效的參數:

class Student(object):
    ...

    def set_score(self, score):
        if 0 <= score <= 100:
            self.__score = score
        else:
            raise ValueError('bad score')
           

需要注意的是,在Python中,變量名類似

__XXX__

的,也就是以雙下劃線開頭,并且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接通路的,不是private變量,是以,不能用

__name__

__score__

這樣的變量名。

有些時候,你會看到以一個下劃線開頭的執行個體變量名,比如:

_name

,這樣的執行個體變量外部是可以通路的,但是,按照約定俗成的規定,當你看到這樣的變量時,意思就是,“雖然我可以被這樣通路,但是,請把我視為私有變量,不要随意通路”。

雙下劃線開頭的執行個體變量是不是一定不能從外部通路呢?其實也不是,不能直接通路

__name

是因為Python解釋器對外把

__name

變量改成了

_Student__name

,是以,仍然可以通過

_Student__name

來通路

__name

變量:

>>> bart._Student__name
'Bart Simpson'
           

但是強烈建議你不要這麼幹,因為不同版本的Python解釋器可能會把

__name

改成不同的變量名。

總的來說就是,Python本身沒有任何機制阻止你幹壞事一切全靠自覺。

最後注意下面這種錯誤寫法:

>>> bart = Student('Bart Simpson', 59 )
>>> bart.get_name()
'Bart Simpson'
>>> bart.__name = 'New Name'
>>> bart.__name
'New Name'
           

表面上看,外部代碼“成功”地設定了

__name

變量,但實際上

__name

變量和class内部的

__name

變量不是一個變量!内部的

__name

變量已經被Python解釋器自動改成了

_Student__name

,而外部代碼給

bart

新增了一個

__name

變量。

>>> bart.get_name() # get_name()内部傳回self.__name
'Bart Simpson'