1. 程式人生 > >封裝、property和綁定方法

封裝、property和綁定方法

you integer 第一個 做到 參數 bmi 內部 定義數據 實例化

一、封裝

1.定義

  封:指的是該屬性對外是隱藏的,但是對內部是開放的

  裝:申請一個名稱空間,往裏邊丟名字和屬性

2.為什麽要有封裝

  2.1 封裝數據屬性的目的:

  首先定義數據屬性的目的就是為了給類外部使用的,隱藏之後就是為了不讓外部直接使用,需要通過調用類內部開通的接口來使用;然後類外部需要用到這個功能的時候,可以通過這個接口來間接的調用並操作這個隱藏屬性。

  精髓:我們可以在該接口上附加上任何我們想要的邏輯與功能,從而達到嚴格控制使用者對屬性的操作。

  2.2 封裝函數屬性的目的:

  定義函數屬性的目的就是為了給類外部使用的,隱藏函數屬性的目的就是為了不讓外部直接使用,須在類的內部開辟一個專門的接口;外部需要使用是,也是需通過這個接口來間接的調用並操作這個隱藏的函數屬性。

  精髓:隔離了復雜的程度

3.如何做到封裝

  可以在需要隱藏的屬性前面加上__開頭

  解釋:

  3.1 這種隱藏僅僅是一種語法上的變形操作。

  3.2 變形操作只在類的定義階段發生一次,因為類體代碼僅僅只在定義階段檢測一次。

  3.3 這種隱藏是對外不對外的,即在類的內部可以直接訪問而在外部不能直接訪問;究其根本原因是在類的定義階段,類體的代碼發生了一次統一的變形。

  3.4 如果不想讓子類的方法覆蓋父類的,可以直接在子類的方法名前加上__開頭,隱藏其屬性。

技術分享圖片
 1 class People():
 2     def __init__(self,name,age):
 3         self.__name
=name 4 self.__age=age 5 def tell_info(self): 6 print(%s - %s%(self.__name,self.__age)) 7 def reset_info(self,name,age): 8 self.__name = name 9 self.__age = age 10 if type(name) is not str: # 在接口上可以添加我們想要的邏輯 11 raise NameError(name must be string
) 12 if type(age) is not int: 13 raise TypeError(age must be integer) 14 15 p1=People(大仙,999) 16 # print(p1.name) # 外部已經訪問不到該屬性了 17 p1.tell_info() 18 p1.reset_info(瓶蓋,9) # 通過類內部定義的特定接口來更改數據 19 p1.tell_info()
封裝的簡單例子

二、property

  property 將被裝飾的方法偽裝成一個數據屬性,這樣在使用時就可以不用加括號而直接引用。

技術分享圖片
class People:
    def __init__(self,name,height,weight):
        self.name=name
        self.weight=weight
        self.height=height

    @property
    def BMI(self):
        return self.weight/(self.height**2)


p=People(黃山,1.7,75)
print(p.BMI) # 可以不用加括號而直接調用
property
 1 class People:
 2     def __init__(self,name):
 3         self.__name=name
 4 
 5     # 將name函數偽裝成一個普通的數據屬性
 6     @property    # 查看obj.name
 7     def name(self):
 8         return your name is %s %self.__name
 9 
10     @name.setter    # 修改obj.name的值
11     def name(self,name):
12         if type(name) is not str:
13             raise NameError(your name must be str )
14         self.__name=name
15         # 相當於在類的內部提供了一個專門修改名字的接口
16 
17     @name.deleter  # 刪除obj.name
18     def name(self):
19         raise PermissionError(Deleting the name is not permission)
20         # del self.__name  # 若要刪除obj.name這個屬性,可以註釋掉上面的raise error,
21                            # 相當於在類的內部提供了一個專門刪除obj.name的接口
22 
23 p=People(大佬)
24 print(p.name)  # 可以不直接加括號而直接引用
25 
26 # p.name=123
27 # print(p.name)  #NameError: your name must be str
28 
29 del p.name  #NameError: your name must be str

三、綁定方法和非綁定方法

1.定義

1.1 綁定方法

綁定方法分成兩類:

  1.1.1 綁定給對象

    在類內部定義的函數且沒有被任何函數裝飾器修飾的,這種就是默認綁定給對象的

  1.1.2 綁定給類

    在類內部定義的函數如果被裝飾器@classmethod 裝飾的,這個函數就是綁定給類的,就應該由類來調用,類來調用就會將類當作第一個參數自動傳入。

  1.1.3 綁定方法的特性:

    綁定給誰就應該由誰來調用,誰來調用就會將誰當成第一個參數自動傳入<其精髓就在於:自動傳值>

1.2 非綁定方法

  類中定義的函數如果被裝飾器@staticmethod 裝飾,那麽該函數就變成非綁定方法。

  函數如果沒有被綁定,則意味著類和對象皆可調用,但無論誰來調用,都沒有自動傳值的效果,就是一個普通的函數,這種情況則應該傳入相應的參數。

2. 如何使用

  如果函數體代碼需要使用外部傳入的類,則應該將函數定義成綁定成給類的方法

  如果函數體代碼需要使用外部傳入的對象,則應該將函數定義成綁定給對象的方法

  如果函數體代碼既不需要使用外部傳入的類,也不需要使用外部傳入的對象,那麽應該將函數定義成非綁定方法/普通函數。

技術分享圖片
 1 import settings
 2 import uuid
 3 
 4 class Mysql():
 5     def __init__(self,ip,port):
 6         self.uuid=self.create_uuid()
 7         self.ip=ip
 8         self.port=port
 9 
10     def get_info(self):
11         print(%s - %s%(self.ip,self.port))
12 
13     @classmethod
14     def from_settings(cls):
15         return cls(settings.ip,settings.port)
16 
17     @staticmethod
18     def create_uuid():  # 非綁定方法,所以不需要參數
19         return uuid.uuid4()
20 
21 # 默認的實例化方式
22 obj=Mysql(192.168.0.0,3306)
23 obj.get_info()  # 這種情況下函數是已經執行了,
24             # 所以不必在用print(obj.get_info())了,
25             # 否則在輸出結果的同時,會收到一個函數的默認返回值
26 
27 # 一種新的實例化方式,從配置文件中讀取出配置完成實例化
28 obj=Mysql.from_settings()
29 obj.get_info()
30 
31 # 若函數是非綁定方法,則類和對象皆可調用
32 obj.create_uuid()
33 Mysql.create_uuid()
小實例 技術分享圖片
ip=192.168.0.0
port=3306
settings

封裝、property和綁定方法