前言
養成一個好的習慣只需要堅持21天,Day9
訪問限制
由上一節定義的Student類來看,我們可以在外部代碼修改name、score屬性。比如我們想要修改對象的成績,可以直接對score
賦值。
bart.score = 60
print(bart.score)
# 60
如果要讓內部的屬性不被外部訪問和修改,我們可以在屬性的名稱前面加上兩個下劃線__
,這樣就變成了一個私有對象,只有內部可以訪問,外部不可以訪問。即在外部即不能訪問也不能進行修改。
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))
bart = Student('Bart Simpon',99)
在外部訪問實例變量的屬性:
bart.__name
# ---------------------------------------------------------------------------
# AttributeError Traceback (most recent call last)
# <ipython-input-2-b54cbc8ec6d2> in <module>()
# ----> 1 bart.__name
#AttributeError: 'Student' object has no attribute '__name'
這樣確保了外部代碼不能隨便的改變對象內部的狀態,如果在限制訪問的同時想要允許外部代碼進行訪問或者修改的話,就可以給類增加get
和set
方法。
class Student(object):
...
# get方法,獲取對象的name、score屬性
def get_name(self):
return self.__name
def get_score(self):
return self.score
# set方法,改變對象的name、score屬性
def set_name(self,name):
self.__name = name
def set_score(self,score):
if 0 <=score<= 100:
self.__score = score
else:
raise ValueError('bad score')
在Python中,類似__xxx__
的變量是特殊變量,特殊變量在外部是可以訪問的,不是私有變量。有時候我們會看到一個下劃線開頭的變量名,比如_name
,這樣命名的意思是“雖然我可以被訪問,但是請把我視爲私有變量,不要隨意訪問。”
雙線劃線開頭的變量也不是一定不能訪問,而是不能直接訪問,如果使用baer._Student__name
來訪問也可以等到name
變量。
bart._Student__name
# 'Bart Simpson'
練習
請把下面的Student對象的gender字段對外隱藏起來,用get_gender()和set_gender()代替,並檢查參數有效性:
class Student(object):
def __init__(self, name, gender):
self.name = name
self.__gender = gender
def get_gender(self):
return self.__gender
def set_gender(self,gender):
if gender in ('male','female'):
self.__gender = gender
else:
raise ValueError('bad gender')
# 測試:
bart = Student('Bart', 'male')
if bart.get_gender() != 'male':
print('測試失敗!')
else:
bart.set_gender('female')
if bart.get_gender() != 'female':
print('測試失敗!')
else:
print('測試成功!')
# 測試成功!
繼承和多態
在OOP程序設計中,當我們定義一個class類時,我們可以從已有的class繼承,新的class類成爲子類(Subclass),原有的class稱爲父類(Base class)。
首先,我們編寫一個animal
類,使用run()
方法直接打印:
class Animal(object):
def run(self):
print('Animal is running...')
繼續編寫Dog
和Cat
類時,就可以直接從Animal
類繼承,把Animal
寫在類名後面的括號裏,就代表Dog
繼承Animal
類,Cat
同理:
class Dog(Animal):
pass
class Cat(Animal):
pass
繼承之後,子類獲得了父類的全部功能。在此處,Dog
和Cat
類就繼承了Animal
類的run()
方法。
dog = Dog()
dog.run()
cat = Cat()
cat.run()
# Animal is running...
# Animal is running...
接着對子類增加一些方法:
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
對子類增加方法後執行:
dog = Dog()
dog.run()
cat = Cat()
cat.run()
# Dog is running...
# Cat is running...
雖然子類繼承的父類中也有run()
方法,但是子類的run()
覆蓋了父類的run()
,這就是繼承的多態表現。要判斷一個變量是否是某個類型可以使用isinstance()
判斷:
b = Dog()
isinstance(b,Dog)
# true