亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python面向?qū)ο缶幊獭庋b

系統(tǒng) 1754 0

Python面向?qū)ο缶幊獭庋b

從封裝本身的意思去理解,封裝就好像是拿來一個(gè)麻袋,把小貓,小狗,小王八,還有alex一起裝進(jìn)麻袋,然后把麻袋封上口子。照這種邏輯看,封裝=‘隱藏’,這種理解是相當(dāng)片面的。

一、先看如何隱藏

在python中用雙下劃線開頭的方式將屬性隱藏起來(設(shè)置成私有的)

          
            #其實(shí)這僅僅這是一種變形操作
#類中所有雙下劃線開頭的名稱如__x都會(huì)自動(dòng)變形成:_類名__x的形式:

class A:
    __N=0 #類的數(shù)據(jù)屬性就應(yīng)該是共享的,但是語法上是可以把類的數(shù)據(jù)屬性設(shè)置成私有的如__N,會(huì)變形為_A__N
    def __init__(self):
        self.__X=10 #變形為self._A__X
    def __foo(self): #變形為_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在類內(nèi)部才可以通過__foo的形式訪問到.

#A._A__N是可以訪問到的,即這種操作并不是嚴(yán)格意義上的限制外部訪問,僅僅只是一種語法意義上的變形
          
        

這種自動(dòng)變形的特點(diǎn):

1、類中定義的 __x 只能在內(nèi)部使用,如 self.__x ,引用的就是變形的結(jié)果。

2、這種變形其實(shí)正是針對(duì)外部的變形,在外部是無法通過 __x 這個(gè)名字訪問到的。

3、在子類定義的 __x 不會(huì)覆蓋在父類定義的 __x ,因?yàn)樽宇愔凶冃纬闪耍? _子類名__x ,而父類中變形成了: _父類名__x ,即雙下滑線開頭的屬性在繼承給子類時(shí),子類是無法覆蓋的。

這種變形需要注意的問題是:

1、這種機(jī)制也并沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字: _類名__屬性 ,然后就可以訪問了,如 a._A__N

2、變形的過程只在類的定義是發(fā)生一次,在定義后的賦值操作,不會(huì)變形。

Python面向?qū)ο缶幊獭庋b_第1張圖片

3、在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的。

          
            #正常情況
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B


#把fa定義成私有的,即__fa
>>> class A:
...     def __fa(self): #在定義時(shí)就變形為_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只會(huì)與自己所在的類為準(zhǔn),即調(diào)用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A
          
        

二、封裝不是單純意義的隱藏

1、封裝數(shù)據(jù)

將數(shù)據(jù)隱藏起來這不是目的。隱藏起來然后對(duì)外提供操作該數(shù)據(jù)的接口,然后我們可以在接口附加上對(duì)該數(shù)據(jù)操作的限制,以此完成對(duì)數(shù)據(jù)屬性操作的嚴(yán)格控制。

          
            class Teacher:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age

    def tell_info(self):
        print('姓名:%s,年齡:%s' %(self.__name,self.__age))
    def set_info(self,name,age):
        if not isinstance(name,str):
            raise TypeError('姓名必須是字符串類型')
        if not isinstance(age,int):
            raise TypeError('年齡必須是整型')
        self.__name=name
        self.__age=age

t=Teacher('egon',18)
t.tell_info()

t.set_info('egon',19)
t.tell_info()
          
        

2、封裝方法:目的是隔離復(fù)雜度

          
            #取款是功能,而這個(gè)功能有很多功能組成:插卡、密碼認(rèn)證、輸入金額、打印賬單、取錢
#對(duì)使用者來說,只需要知道取款這個(gè)功能即可,其余功能我們都可以隱藏起來,很明顯這么做
#隔離了復(fù)雜度,同時(shí)也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用戶認(rèn)證')
    def __input(self):
        print('輸入取款金額')
    def __print_bill(self):
        print('打印賬單')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()
          
        

封裝方法的其他舉例:

1、你的身體沒有一處不體現(xiàn)著封裝的概念:你的身體把膀胱尿道等等這些尿的功能隱藏了起來,然后為你提供一個(gè)尿的接口就可以了(接口就是你的。。。,),你總不能把膀胱掛在身體外面,上廁所的時(shí)候就跟別人炫耀:hi,man,你瞅我的膀胱,看看我是怎么尿的。

2、電視機(jī)本身是一個(gè)黑盒子,隱藏了所有細(xì)節(jié),但是一定會(huì)對(duì)外提供了一堆按鈕,這些按鈕也正是接口的概念,所以說,封裝并不是單純意義的隱藏!!!

3、快門就是傻瓜相機(jī)為傻瓜們提供的方法,該方法將內(nèi)部復(fù)雜的照相功能都隱藏起來了。

注:在編程語言里,對(duì)外提供的接口(接口可理解為了一個(gè)入口),可以是函數(shù),稱為接口函數(shù),這與接口的概念還不一樣,接口代表一組接口函數(shù)的集合體。

三、特性(property)

1、什么是特性property

property是一種特殊的屬性,訪問它時(shí)會(huì)執(zhí)行一段功能(函數(shù))然后返回值。

例一:BMI指數(shù)(bmi是計(jì)算而來的,但很明顯它聽起來像是一個(gè)屬性而非方法,如果我們將其做成一個(gè)屬性,更便于理解)。

成人的BMI數(shù)值:

過輕:低于18.5

正常:18.5-23.9

過重:24-27

肥胖:28-32

非常肥胖, 高于32

體質(zhì)指數(shù)(BMI)=體重(kg)÷身高^2(m)

EX:70kg÷(1.75×1.75)=22.86

          
            class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height
    @property
    def bmi(self):
        return self.weight / (self.height**2)

p1=People('egon',75,1.85)
print(p1.bmi)
          
        

例二:圓的周長和面積

          
            import math
class Circle:
    def __init__(self,radius): #圓的半徑radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #計(jì)算面積

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #計(jì)算周長

c=Circle(10)
print(c.radius)
print(c.area) #可以向訪問數(shù)據(jù)屬性一樣去訪問area,會(huì)觸發(fā)一個(gè)函數(shù)的執(zhí)行,動(dòng)態(tài)計(jì)算出一個(gè)值
print(c.perimeter) #同上
'''
輸出結(jié)果:
314.1592653589793
62.83185307179586
'''
          
        

注:此時(shí)的特性area和perimeter不能被賦值

          
            c.area=3 #為特性area賦值
'''
拋出異常:
AttributeError: can't set attribute
'''
          
        

2、為什么要用property

將一個(gè)類的函數(shù)定義成特性以后,對(duì)象再去使用的時(shí)候obj.name,根本無法察覺自己的name是執(zhí)行了一個(gè)函數(shù)然后計(jì)算出來的,這種特性的使用方式 遵循了統(tǒng)一訪問的原則

除此之外,看下

          
            ps:面向?qū)ο蟮姆庋b有三種方式:
【public】
這種其實(shí)就是不封裝,是對(duì)外公開的
【protected】
這種封裝方式對(duì)外不公開,但對(duì)朋友(friend)或者子類(形象的說法是“兒子”,但我不知道為什么大家 不說“女兒”,就像“parent”本來是“父母”的意思,但中文都是叫“父類”)公開
【private】
這種封裝對(duì)誰都不公開
          
        

python并沒有在語法上把它們?nèi)齻€(gè)內(nèi)建到自己的class機(jī)制中,在C++里一般會(huì)將所有的所有的數(shù)據(jù)都設(shè)置為私有的,然后提供set和get方法(接口)去設(shè)置和獲取,在python中通過property方法可以實(shí)現(xiàn)。

          
            class Foo:
    def __init__(self,val):
        self.__NAME=val #將所有的數(shù)據(jù)屬性都隱藏起來

    @property
    def name(self):
        return self.__NAME #obj.name訪問的是self.__NAME(這也是真實(shí)值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在設(shè)定值之前進(jìn)行類型檢查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通過類型檢查后,將值value存放到真實(shí)的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #拋出異常'TypeError: 10 must be str'
del f.name #拋出異常'TypeError: Can not delete'
          
        

四、封裝與可擴(kuò)展性

封裝在于明確區(qū)分內(nèi)外,使得類實(shí)現(xiàn)者可以修改封裝內(nèi)的東西而不影響外部調(diào)用者的代碼;而外部使用用者只知道一個(gè)接口(函數(shù)),只要接口(函數(shù))名、參數(shù)不變,使用者的代碼永遠(yuǎn)無需改變。這就提供一個(gè)良好的合作基礎(chǔ)——或者說,只要接口這個(gè)基礎(chǔ)約定不變,則代碼改變不足為慮。

          
            #類的設(shè)計(jì)者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #對(duì)外提供的接口,隱藏了內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),此時(shí)我們想求的是面積
        return self.__width * self.__length


#使用者
>>> r1=Room('臥室','egon',20,20,20)
>>> r1.tell_area() #使用者調(diào)用接口tell_area


#類的設(shè)計(jì)者,輕松的擴(kuò)展了功能,而類的使用者完全不需要改變自己的代碼
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #對(duì)外提供的接口,隱藏內(nèi)部實(shí)現(xiàn),此時(shí)我們想求的是體積,內(nèi)部邏輯變了,只需求修該下列一行就可以很簡答的實(shí)現(xiàn),而且外部調(diào)用感知不到,仍然使用該方法,但是功能已經(jīng)變了
        return self.__width * self.__length * self.__high


#對(duì)于仍然在使用tell_area接口的人來說,根本無需改動(dòng)自己的代碼,就可以用上新功能
>>> r1.tell_area()
          
        

更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 久久影院视频 | 精品国产日韩一区三区 | 亚洲国产99在线精品一区二区 | 欧美黄色录像视频 | 色偷偷久久 | 天天天天天天操 | 在线视频欧美日韩 | 四虎精品久久久久影院 | 黄色男人的天堂 | 日本精品一区二区三区视频 | 午夜视频久久 | 99这里精品| 欧美黑大粗硬毛片视频 | 欧美 日韩 国产在线 | 成人欧美一区二区三区在线观看 | 国产亚洲人成a在线v网站 | 国产亚洲综合精品一区二区三区 | 亚洲天堂二区 | 在线免费观看一级毛片 | 97在线免费看视频 | 一级免费毛片 | 一区二区三区精品国产欧美 | 嗯啊在线观看免费影院 | 天天干天天插天天射 | 国产97在线观看 | 欧美久久网 | 四虎影院永久网址 | 草久视频在线观看 | 久久久久久久久国产 | 日本a∨在线播放高清 | 四库国产精品成人 | 欧美日韩精品一区二区三区四区 | 国产激情视频一区二区三区 | 黄色小视频免费看 | 波多野结衣亚洲一区二区三区 | 四虎永久地址入口 | 人人澡人人澡人人看欧美 | 99热最新网址 | 亚洲成综合 | 亚洲国产婷婷综合在线精品 | 九九热视频这里只有精品 |