python封裝

封裝

1、封裝是什麼意思?

從封裝自己的意思去理解,封裝就好像是拿來一個麻袋,把小貓,小狗,小王八,一塊兒裝進麻袋,而後把麻袋封上口子# 如何隱藏,把東西包裝進去以後,隱藏起來,外部訪問不到,可是比較片面。編程

2、爲何要封裝

封裝數據的主要緣由是:保護隱私(做爲男人的你,臉上就寫着:我喜歡男人,你懼怕麼?)安全

封裝方法的主要緣由是:隔離複雜度(快門就是傻瓜相機爲傻瓜們提供的方法,該方法將內部複雜的照相功能都隱藏起來了,好比你沒必要知道你本身的尿是怎麼流出來的,你直接掏出本身的接口就能用尿這個功能)socket

class Person:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age
    def __speak(self):
        print('6666')

p=Person('nick',89)
# p.__speak()
print(Person.__dict__)
p._Person__speak()

提示:在編程語言裏,對外提供的接口(接口可理解爲了一個入口),就是函數,稱爲接口函數,這與接口的概念還不同,接口表明一組接口函數的集合體。編程語言

3、倆個層面的封裝

封裝其實分爲兩個層面,但不管哪一種層面的封裝,都要對外界提供好訪問你內部隱藏內容的接口(接口能夠理解爲入口,有了這個入口,使用者無需且不可以直接訪問到內部隱藏的細節,只能走接口,而且咱們能夠在接口的實現上附加更多的處理邏輯,從而嚴格控制使用者的訪問)函數

3.1 第一個層面(隱藏)

第一個層面的封裝(什麼都不用作):建立類和對象會分別建立兩者的名稱空間,咱們只能用類名.或者obj.的方式去訪問裏面的名字,這自己就是一種封裝code

注意:對於這一層面的封裝(隱藏),類名.和實例名.就是訪問隱藏屬性的接口對象

#如何用代碼實現隱藏
#隱藏屬性/隱藏方法 隱藏以後,外部訪問不到,只有內部可以訪問
    # 隱藏屬性:經過 __變量名來隱藏
    # 隱藏方法:經過 __方法名來隱藏
#name 隱藏起來
# 隱藏屬性是爲了安全
class Person:
    def __init__(self,name,age):
        self.__name=name##在定義的時候前面加上__能夠隱藏,外部訪問不到
        self.__age=age
    def get_name(self):
        # print(self.__name)
        return '[----%s-----]'%self.__name

p=Person('nick',89)
# print(p.age)
# # 訪問name
# print(p.name)
# print(p.__name)
print(p.get_name())

3.1.1隱藏後如何實現調用

class Person:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age
    def __speak(self):
        print('6666')

p=Person('nick',89)
# p.__speak()
print(Person.__dict__)#查看類的全部方法和屬性,根據方法屬性進行調用
p._Person__speak()


#

{'__module__': '__main__', '__init__': <function Person.__init__ at 0x000001C87F3174C8>, '_Person__speak': <function Person.__speak at 0x000001C87F317438>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}




6666

3.2 第二個層面

第二個層面的封裝:類中把某些屬性和方法隱藏起來(或者說定義成私有的),只在類的內部使用、外部沒法訪問,或者留下少許接口(函數)供外部訪問。繼承

在python中用雙下劃線的方式實現隱藏屬性(設置成私有的)接口

類中全部雙下劃線開頭的名稱如__x都會自動變造成:_類名__x的形式:

class A:
    __N = 0  # 類的數據屬性就應該是共享的,可是語法上是能夠把類的數據屬性設置成私有的如__N,會變形爲_A__N

    def __init__(self):
        self.__X = 10  # 變形爲self._A__X

    def __foo(self):  # 變形爲_A__foo
        print('from A')

    def bar(self):
        self.__foo()  # 只有在類內部才能夠經過__foo的形式訪問到.

這種自動變形的特色:

  1. 類中定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。
  2. 這種變形其實正是針對內部的變形,在外部是沒法經過__x這個名字訪問到的。
  3. 在子類定義的__x不會覆蓋在父類定義的__x,由於子類中變造成了:_子類名__x,而父類中變造成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是沒法覆蓋的。

注意:對於這一層面的封裝(隱藏),咱們須要在類中定義一個函數(接口函數)在它內部訪問被隱藏的屬性,而後外部就可使用了

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

  1. 這種機制也並無真正意義上限制咱們從外部直接訪問屬性,知道了類名和屬性名就能夠拼出名字:_類名__屬性,而後就能夠訪問了,如a._A__N

3.3屬性何時會變形

何時屬性變形,只要再類內部,以__變量名 命名的變量,都會被隱藏,會發生的變形,在外部放入的 __變量名 屬性是不隱藏的

#何時屬性變形,只要再類內部,以__變量名 命名的變量,都會被隱藏,會發生的變形,在外部放入的  __變量名 屬性是不隱藏的
# class Person:
#     def __init__(self,name,age):
#         self.__name=name
#         self.__age=age
#     def set_xx(self,xx):
#         self.__xx=xx
#
# p=Person('nick',18)
# # ._p_xx="xxx"
#
# p.set_xx('6688')
# print(p.__dict__)

3.4計算人的bmi指數

#計算人的bmi指數
#property裝飾器:把方法包裝成數據屬性
class Person:
    def __init__(self,name,height,weight):
        self.name=name
        self.height=height
        self.weight=weight
    @property
    def bmi(self):
        return self.weight/(self.height**2)
        # return self.weight/(self.height*self.height)
p=Person('lqz',1.82,70)
# print(p.bmi())
print(p.bmi)
# p.name='ppp'
p.bmi=90

4、私有模塊

python並不會真的阻止你訪問私有的屬性,模塊也遵循這種約定,若是模塊中的變量名_private_module以單下劃線開頭,那麼from module import *時不能被導入該變量,可是你from module import _private_module依然是能夠導入該變量的

其實不少時候你去調用一個模塊的功能時會遇到單下劃線開頭的(socket._socket,sys._home,sys._clear_type_cache),這些都是私有的,原則上是供內部調用的,做爲外部的你,獨斷獨行也是能夠用的,只不過顯得稍微傻逼一點點

python要想與其餘編程語言同樣,嚴格控制屬性的訪問權限,只能藉助內置方法如__getattr__,詳見面向對象高級部分。

5、封裝中的裝飾器

property之setter和deleter

class Person:
    def __init__(self,name,height,weight):
        self.__name=name
        self.__height=height
        self.__weight=weight
    @property
    def name(self):
        return '[個人名字是:%s]'%self.__name
    #用property裝飾的方法名.setter
    @name.setter
    def name(self,new_name):
        # if not isinstance(new_name,str):
        if type(new_name) is not str:
            raise Exception('改不了')
        if new_name.startswith('sb'):
            raise Exception('不能以sb開頭')
        self.__name=new_name

    # 用property裝飾的方法名.deleter
    @name.deleter
    def name(self):
        # raise Exception('不能刪')
        print('刪除成功')
        # del self.__name

p=Person('lqz',1.82,70)
# print(p.name)
# p.name='pppp'
# p.name='xxx'
#改不了,直接拋一異常
# p.name=999
# p.name='sb_nick'

# print(p.name)

del p.name
print(p.name)
相關文章
相關標籤/搜索