網站首頁 編程語言 正文
一 封裝的概念
封裝其實在我們的生活中處處都是,如電視機,電腦,手機等物品。我們通常只能看到其外部的形狀,以及使用他們提供的功能,并不能看到其內部復雜的硬件組成,這些都是封裝好的,不能讓我們看到,避免我們的一些“特殊”操作,使其不能正常工作。編程源于生活。在python
中也有對對象的封裝操作,使其對外只提供固定的訪問模式,不能訪問其內部的私有屬性和私有方法。python中的封裝,一般指的是對類屬性,類方法的封裝,即類屬性私有化和類方法私有化,具體如下面的小結所講。
二 _ 和__ 對屬性和方法的私有化
1. 單下劃線_
當類中的屬性和方法以_ 單下劃線開頭時,即說明這是類的保護變量和保護方法,按照編碼約定,是不希望被外部訪問的。但如果你要進行訪問,也不會報錯。
如下:
class A(): ? ? #_ 聲明是保護屬性和保護方法 ? ? _name = '張三' ? ? def __init__(self): ? ? ? ? self._age = 23 ? ? def _method(self): ? ? ? ? print("我叫{},今年{}歲".format(self._name, self._age)) if __name__ == '__main__': ? ? a = A() ? ? #打印類A的dir ? ? print(a.__dir__()) ? ? #訪問保護變量和保護方法 ? ? print(a._name) ? ? a._method()
輸出結果:
>>>
['_age', '__module__', '_name', '__init__', '_method', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
張三
我叫張三,今年23歲
可以看出,以_單下劃線開頭的屬性和方法其實在類外部是可以訪問的,但是根據約定,當我們看見這樣的屬性和方法時,不應該在外部對其進行訪問。
2. 雙下劃線__
上面以單下劃線開頭的屬性和方法雖然是保護的,但是在外部還是可以訪問的。而當你看到以雙下劃線__開頭的屬性和方法時,請記住它們是類的私有屬性和私有方法,在類外以及子類中以常規訪問類屬性類方法的方法是無法訪問的,也無法對其進行修改,如下
class B(): ? ? #__ 聲明是私有化的 ? ? __name = '張三' ? ? def __init__(self): ? ? ? ? self.__age = 23 ? ? ? ? self.__luange = 'python' ? ? def __method(self): ? ? ? ? #私有方法 ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? def fun(self): ? ? ? ? #公有方法 ? ? ? ? print("this is a public method") ? ?if __name__ == '__main__': ? ? b = B() ? ? #打印類B的dir ? ? print(b.__dir__()) ? ? #訪問類B的私有屬性和私有方法 ? ? b.fun() ? ? print(b.__name, b.__age, b.__luange) ? ? b.__method()
輸出結果:
>>>
['_B__age', '_B__luange', '__module__', '_B__name', '__init__', '_B__method', 'fun', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
this is a public method
Traceback (most recent call last):
? File "C:/Users/admin/python-learning/python學習文件/python基礎/python類封裝.py", line 56, in
? ? print(b.__name, b.__age, b.__luange)
AttributeError: 'B' object has no attribute '__name'
從結果可以看出,訪問類B的公有方法fun()
是正常輸出的,但是當我們訪問私有屬性name時就拋錯:類B沒有name屬性。上面單下劃線時,我們打印類A的dir,可以看到類A的name
屬性和method
方法在dir里面是下面這樣的
上面我們也打印了類B的私有屬性和私有方法,如下:
可以看到私有屬性和私有方法都變成了_B__屬性和_B__方法的形式,所以我們在上面以__ name或者name的形式去訪問是報錯的,其實我們如果以 類名(). _ 類名__ 屬性(實例屬性)或者類名. _ 類名__ 屬性(類屬性)的形式去訪問,還是會訪問成功的。如下
class B(): ? ? #__ 聲明是私有化的 ? ? __name = '張三' ? ? def __init__(self): ? ? ? ? self.__age = 23 ? ? ? ? self.__luange = 'python' ? ? def __method(self): ? ? ? ? #私有方法 ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? def fun(self): ? ? ? ? #公有方法 ? ? ? ? print("this is a public method") if __name__ == '__main__': ? ? b = B() ? ? #打印類B的dir ? ? print(b.__dir__()) ? ? #訪問類B的私有屬性和私有方法 ? ? b.fun() ? ? print(B._B__name, b._B__age, b._B__luange) ? ? b._B__method()
結果如下:
>>>
['_B__age', '_B__luange', '__module__', '_B__name', '__init__', '_B__method', 'fun', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
this is a public method
張三 23 python
我叫張三,今年23歲,我喜歡python。
3. 子類中訪問父類的私有屬性和私有方法
子類無法訪問父類的私有屬性和私有方法:
class B(): ? ? #__ 聲明是私有化的 ? ? __name = '張三' ? ? def __init__(self): ? ? ? ? self.__age = 23 ? ? ? ? self.__luange = 'python' ? ? def __method(self): ? ? ? ? #私有方法 ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? def fun(self): ? ? ? ? #公有方法 ? ? ? ? print("this is a public method") class C(B): ? ? def __init__(self): ? ? ? ? super().__init__() ? ? def fun1(self): ? ? ? ? #訪問父類B的私有屬性和私有方法 ? ? ? ? print(self.__name, self.__age, self.__luange) ? ? ? ? self.__method() if __name__ == '__main__': ? ? c = C() ? ? c.fun1()
輸出結果:
>>>
AttributeError: 'C' object has no attribute '_C__name'
AttributeError: 'C' object has no attribute '_C__method'
可以看出子類也是無法訪問父類的私有屬性和私有方法的。
當子類中的的屬性和方法與父類的私有屬性,私有方法同名時,不會覆蓋父類的私有屬性和私有方法。
class B(): ? ? #__ 聲明是私有化的 ? ? __name = '張三' ? ? def __init__(self): ? ? ? ? self.__age = 23 ? ? ? ? self.__luange = 'python' ? ? def __method(self): ? ? ? ? #私有方法 ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? def fun(self): ? ? ? ? #公有方法 ? ? ? ? print("this is a public method") class C(B): ? ? __name = '李四' ? ? def __init__(self): ? ? ? ? super().__init__() ? ? ? ? self.__age = 24 ? ? ? ? self.__luange = 'C++' ? ? def fun1(self): ? ? ? ? #訪問父類B的私有屬性和私有方法 ? ? ? ? print(self.__name, self.__age, self.__luange) ? ? ? ? self.__method() ? ? def __method(self): ? ? ? ? #類C的私有方法,與父類方法同名,但不重寫父類方法 ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? ? ? #調用父類的私有方法 ? ? ? ? B()._B__method() if __name__ == '__main__': ? ? c = C() ? ? #訪問類C的私有方法 ? ? c._C__method()
結果如下:
>>>
我叫李四,今年24歲,我喜歡C++。
我叫張三,今年23歲,我喜歡python。
可以看到,子類C并沒有重寫父類B的__method()方法。這是為什么呢?我們打印一下B和C的dir,如下:
>>>
['_B__age', '_B__luange', '_C__age', '_C__luange', 'fun1',
?'_C__method', '__doc__', '_B__name', '_B__method', '_C__name', ...]
可以看到,在類C的dir中,父類B的私有屬性和私有方法是以 _B__屬性(方法)存在的,二類C自己的私有屬性和私有方法是以_C__屬性(方法)存在的,即類的私有屬性和私有方法會以_類名_屬性(方法)的形式存在dir中,所以當子類的屬性和方法與父類的私有屬性和私有方法同名時,并不會覆蓋重寫。
三 訪問及修改類的私有屬性和私有方法
類通過對屬性和方法的私有化,可以對其起到封裝保護作用。但是,當外部需要訪問和改變時怎么辦呢?就像電視機,電腦也會對外提供固定的接口。
上面,雖然我們可以通過類名(). _ 類名__ 屬性(實例屬性)或者類名. _ 類名__ 屬性(類屬性)的形式去訪問類的私有屬性和私有方法,但是這是違反編程規范的,不支持這么做,就像不會拆開電視機對其操作一樣。
正確對類的私有屬性和私有方法進行訪問修改的一般有兩種發方法,如下:
1. 自定義公有方法
class D(): ? ? __name = '張三' ? ? def __init__(self): ? ? ? ? self.__age = 23 ? ? ? ? self.__luange = 'python' ? ? def __method(self): ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? def get_value(self): ? ? ? ? return self.__name, self.__age, self.__luange ? ? def get_method(self): ? ? ? ? self.__method() ? ? def set_value(self, name, age, luange): ? ? ? ? self.__name, self.__age, self.__luange = name, age, luange if __name__ == '__main__': ? ? d = D() ? ? #通過get_value方法訪問私有屬性 ? ? print(d.get_value()) ? ? #通過get_method方法訪問私有方法 ? ? print('=' * 30) ? ? d.get_method() ? ? #通過set_value方法修改私有屬性 ? ? print('='*30) ? ? print(d.get_value()) ? ? d.set_value('王二麻子', 25, 'Linux') ? ? print(d.get_value()) ? ? d.get_method()
輸出結果:
>>>
('張三', 23, 'python')
==============================
我叫張三,今年23歲,我喜歡python。
==============================
('張三', 23, 'python')
('王二麻子', 25, 'Linux')
我叫王二麻子,今年25歲,我喜歡Linux。
可以看到,我們通過自定義的的get_value(),get_method()以及set_value()方法就實現了對私有屬性和私有方法的訪問和修改。
2. property
property一般有兩個作用,如下:
- 作為裝飾器,@property 將類的方法轉為只讀的類屬性
- property 重新實現一個屬性的 getter 和 setter 方法
來看看下面這個E類,如下:
class E(): ? ? __name = '張三' ? ? def __init__(self): ? ? ? ? self.__age = 23 ? ? ? ? self.__luange = 'python' ? ? def __method(self): ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? def get_value(self): ? ? ? ? return self.__name ? ? def set_value(self, name): ? ? ? ? self.__name = name ? ? getValue = property(get_value, set_value) ? ? @property ? ? def get_method(self): ? ? ? ? self.__method() if __name__ == '__main__': ? ? e = E() ? ? #訪問 ? ? print(e.getValue) ? ? e.get_method ? ? #修改 ? ? e.getValue = '王二' ? ? print(e.getValue)
結果:
>>>
張三
我叫張三,今年23歲,我喜歡python。
王二
可以看到,我們將get_value
和set_value
方法傳入property后,類方法就轉換成類屬性,并賦值給getValue變量。此時e.getValue就是只讀,即get_value方法,e.value = ‘王二’ 就是修改,即get_value
方法。同一,通過@propert,將get_method方法,變成了屬性。
下面property
重新實現一個屬性的 getter 和 setter 方法,不同于上面的寫法,較上面常用。
class E(): ? ? __name = '張三' ? ? def __init__(self): ? ? ? ? self.__age = 23 ? ? ? ? self.__luange = 'python' ? ? def __method(self): ? ? ? ? print("我叫{},今年{}歲,我喜歡{}。".format(self.__name, self.__age, self.__luange)) ? ? @property ? ? def name(self): ? ? ? ? return self.__name ? ? @name.setter ? ? def name(self, name): ? ? ? ? self.__name = name if __name__ == '__main__': ? ? e = E() ? ? #訪問 ? ? print(e.name) ? ? #修改 ? ? print("修改前:", e.name) ? ? e.name = '隔壁老王' ? ? print("修改后:", e.name)
輸出結果:
>>>
張三
修改前: 張三
修改后: 隔壁老王
上面是首先把name方法送給propert裝飾器進行裝飾,然后調用裝飾后的setter方法,即可實現對私有屬性進行修改。
原文鏈接:https://blog.csdn.net/qq_44690947/article/details/123243463
相關推薦
- 2022-03-19 C語言常量介紹_C 語言
- 2022-07-12 springboot整合jasypt加密yml配置文件
- 2022-06-07 Docker的四種網絡模式_docker
- 2022-06-12 Go依賴注入DI工具wire使用詳解(golang常用庫包)_Golang
- 2022-07-11 Python利用xlrd?與?xlwt?模塊操作?Excel_python
- 2022-05-19 徹底解決No?module?named?‘torch_geometric‘報錯的辦法_python
- 2022-01-18 在使用npm install時遇到的問題 npm ERR! code ERESOLVE
- 2023-10-12 antd3升級到antd4(已解決所有報錯)
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支