私有屬性包括私有變量和私有方法,在 Python 中,在變量名或者方法名前面加上雙下劃線,這個屬性就成爲了類的私有屬性。
ide
class Person: def __init__(self, name, age): self.__name = name self.__age = age def __fun(self): print(self.__class__) def say(self): self.__fun() # 自動轉換爲 調用 _Person__fun 方法 print(self.__name + ' ' + str(self.__age)) # 自動轉換爲 調用 \_Person\_\_name 和 \_Person\_\_age 屬性~ p = Person('Kitty', 18) p.say() # 輸出結果: Kitty 18
上述示例中,__name 和 __age 爲類的私有變量,私有變量僅能在類中進行訪問,在類的外部訪問不到。函數
p = Person('Kitty', 18) print(p.__name) # 報錯信息: AttributeError: 'Person' object has no attribute '__name'
其實在類中定義私有屬性時,__name 和 __age 已經自動變形爲 _Person__name 和 _Person__age,__fun 自動變形爲 _Person__fun,即私有屬性會自動變形爲_類名__屬性~code
p = Person('Kitty', 18) print(p.__dict__) # 輸出結果: {'_Person__name': 'Kitty', '_Person__age': 18}
當在類的內部經過屬性名稱訪問私有屬性時,會自動進行轉換,例如 self.__name 轉換爲 self._Person__name,在類的外部不會進行這樣的自動轉換~
類的私有屬性只是在語法上作了訪問限制,可是並無真正限制從外部的訪問。在外部不能經過 對象.__屬性 來進行訪問,可是能夠經過變形後的屬性名來進行訪問~對象
p = Person('Kitty', 18) # print(p.__name) # 不能這樣訪問 print(p._Person__name) p._Person__fun() # 結果輸出: Kitty <class '__main__.Person'>
對私有屬性的訪問限制只是一種規範,在開發過程當中通常不容許在外部經過這種方式訪問私有屬性~
私有屬性的變形只在類的內部生效,在定義後的賦值操做,不會變形~blog
p = Person('Kitty', 18) p.__name = 'abc' print(p.__dict__) print(p.__name) # 調用的是 __name 屬性,不是私有屬性 # 輸出結果: {'_Person__name': 'Kitty', '_Person__age': 18, '__name': 'abc'} # 這個屬性就叫 __name abc
在子類中定義的私有屬性如果和父類中的私有屬性同名,不會覆蓋父類的這些私有屬性,由於這些私有屬性變形後的名稱不一樣,子類:_子類名__屬性,父類:_父類名__屬性~ip
class Fu: __key = 123 # 靜態私有屬性 def __init__(self, name): self.__name = name class Zi(Fu): def get_name(self): print(self.__name) # 變形爲 self._Zi__name def get_key(self): print(Fu.__key) # 變形爲 self._Zi__key zi = Zi('hello') zi.get_name() # 報錯信息:AttributeError: 'Zi' object has no attribute '_Zi__name' zi.get_key() # 報錯信息:AttributeError: type object 'Fu' has no attribute '_Zi__key'
如果父類中定義的方法不想被子類調用到,能夠將方法定義爲私有方法~開發
class A: def __fun(self): # 在定義時就變形爲_A__fun print('from A') def test(self): self.__fun() # 變形爲 self._A__fun(),即以當前的類爲準 class B(A): def __fun(self): print('from B') b=B() b.test() # 調用 A類中的test方法,test方法中的 self.__fun() 調用的是 A類中的私有方法__fun() # 輸出結果: from A
封裝的優點在於將類內部的實現細節隱藏起來,調用者無需瞭解,直接調用對應的方法便可(方法名,參數都不改變),若功能須要改變,只須要在類的內部進行調整,外部的調用代碼無需改變~get
property爲內置裝飾器函數,只在面向對象中使用。@property裝飾器 能夠將 對方法的調用轉爲 對變量的調用。示例以下:it
class Person: def __init__(self, name, age): self.__name = name self.__age = age @property def name(self): return self.__name @property def age(self): return self.__age p = Person('Kitty', 18) print(p.name) print(p.age) # 結果輸出: Kitty 18
p.name 和 p.age 實際上是執行了一個函數,而後將結果返回。這種特性的使用方式遵循了統一訪問的原則。
p.屬性 的這個過程也能夠作一些運算操做而後將結果返回~class
class Room: def __init__(self, width, length, high): self.__width = width self.__length = length self.__high = high def area(self): return self.__width * self.__length * self.__high room = Room(1, 2, 3) print(room.area()) # 6
除了 @property,還有 @屬性.setter和 @屬性.deleter,要注意的是,定義了 property 後才能定義 屬性.setter,屬性.deleter ~
class Person: def __init__(self, name, age): self.__name = name self.__age = age @property def name(self): return self.__name @name.setter def name(self, value): if not isinstance(value, str): # 在設定值以前進行類型檢查 raise TypeError('%s must be str' %value) self.__name = value @name.deleter def name(self): raise TypeError('Can not delete') @property def age(self): return self.__age p = Person('Kitty', 18) p.name = 'nihao' print(p.name) del p.name # TypeError: Can not delete
說明:
執行 p.name 的時候,調用 @name.setter 修飾的方法,這樣的賦值方式在真正的賦值以前能夠作一些類型檢驗的操做,或者別的自定義操做,更具靈活性~
執行 del p.name 的時候,調用 @name.deleter 修飾的方法
在使用 @property,@屬性.setter 和 @屬性.deleter 的時候,這幾個地方必須保持一致,即屬性名稱須要保持一致。
上述示例也能夠經過以下方式實現:
class Person: def __init__(self, name, age): self.__name = name self.__age = age def get_name(self): return self.__name def set_name(self, value): if not isinstance(value, str): # 在設定值以前進行類型檢查 raise TypeError('%s must be str' %value) self.__name = value def del_name(self): print('delete name') name = property(get_name, set_name, del_name) @property def age(self): return self.__age
Tip:
.................^_^