1. 程式人生 > >Python封裝與隱藏

Python封裝與隱藏

per height 思考 語法 strong 文件 ron 問題: div

今日內容:

1.封裝與隱藏
2.property
3.綁定方法與非綁定方法

知識點一:封裝與隱藏

  

  1、什麽封裝:
    封:屬性對外是隱藏的,但對內是開放的
    裝:申請一個名稱空間,往裏裝入一系列名字/屬性

  2、為什麽要封裝:
   封裝數據屬性的目的
    首先定義屬性的目的就是為了給類外部的使用者使用的,
    隱藏之後是為了不讓外部使用者直接使用,需要類內部開辟一個接口
    然後讓類外部的使用通過接口來間接地操作隱藏的屬性。
    精髓在於:我們可以在接口之上附加任意邏輯,從而嚴格控制使用者對屬性的操作

   封裝函數屬性:
    首先定義屬性的目的就是為了給類外部的使用使用的,
    隱藏函數屬性是為了不讓外不直接使用,需要類內部開辟一個接口
    然後在接口內去調用隱藏的功能
  精髓在於:隔離了復雜度

  3、如何隱藏:

    1、 這種隱藏僅僅只是一種語法上的變形操作
    2、 這種語法上的變形只在類定義階段發生一次,因為類體代碼僅僅只在類定義階段檢測一次
    3、 這種隱藏是對外不對內的,即在類的內部可以直接訪問,而在類的外則無法直接訪問,原因是
    在類定義階段,類體內代碼統一發生了一次變形

    4、 如果不想讓子類的方法覆蓋父類的,可以將該方法名前加一個__開頭

 1 class People:
 2     def __init__(self,name,age):
 3         self.__name=name
 4         self.__age
=age 5 6 def tell_info(self): 7 print(%s:%s %(self.__name,self.__age)) 8 9 def set_info(self,name,age): 10 if type(name) is not str: 11 # print(‘用戶名必須為str類型‘) 12 # return 13 raise TypeError(用戶名必須為str類型) 14 15 if type(age) is
not int: 16 # print(‘年齡必須為int類型‘) 17 # return 18 raise TypeError(年齡必須為int類型) 19 self.__name=name 20 self.__age=age 21 22 peo1=People(張三,34) 23 # peo1.name=123 24 # peo1.age 25 peo1.tell_info() 26 27 peo1.set_info(李四,19) 28 peo1.tell_info()

知識點二:property裝飾

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

 1 》》》@propertyde思路演變的過程
 2 版本1:正常版本
 3 class People:
 4     def __init__(self,name,weight,height):
 5         self.name=name
 6         self.weight=weight
 7         self.height=height
 8 
 9     def bmi(self):
10         return self.weight / (self.height**2)
11 
12 peo=People(‘張三,130,1.65)
13 print(peo.name)   #張三
14 print(peo.bmi())   #47.75022956841139
15 
16 問題:發現bmi的訪問方式比訪問對象屬性多了個()
17 思路變化1:正常情況下我們訪問對象裏面屬性和類裏面的函數方式為:
18 思路變化2:為了方便用戶調用,能不能讓用戶已訪問對象屬性的方式去訪問bmi print(peo.bmi)
 1 》》》》》》版本2:@property初始版本
 2 #思考:如何實現改變訪問bmi的方式為》》》print(peo.bmi)
 3 #      使用@property:作用是將本裝飾的方法偽裝成一個數據類型,在使用時可以不用加括號而直接使用
 4 
 5 class People:
 6     def __init__(self,name,weight,height):
 7         self.name=name
 8         self.weight=weight
 9         self.height=height
10 
11     @property        #將bmi偽裝成一個數據類型
12     def bmi(self):
13         return self.weight / (self.height**2)
14 
15 peo=People(張三,130,1.65)
16 print(peo.name)   #張三
17 print(peo.bmi)    #這樣可以直接調用而不用加括號

 1 》》》》》完整版:@property
 2 #property裝飾器
 3 #是一種封裝思想的體現,方便了查 刪 改
 4 
 5 class people:
 6     def __init__(self,name):
 7         self.__name=name
 8 
 9     @property
10     def name(self):            #查看obj.name
11         return 名字是:%s%self.__name
12 
13     @name.setter              #更改obj.name=name
14     def name(self,name):
15         if type(name) is not str:
16             raise TypeError(名字必須是str類型)
17         self.__name=name
18     @name.deleter           #刪除 del obj.name
19     def name(self):
20         print(不讓刪除)  #裏面可以設定提示
21         # del self.__name      #也可以設定直接刪除功能
22 
23 peo=people(張三)
24 #默認不加@property調用方法為:
25 
26 peo.name=李四  #@name.setter 調用了更改
27 print(peo.name)    #@property 調用了查看                  輸出結果:名字是:李四
28 del peo.name       #@name.deleter  調用了產出的需求       輸出結果:不讓刪除

知識點三:綁定方法

  1.綁定方法
    特性:綁定給誰就應該由誰來調用,誰來調用就會將誰當做第一個參數自動傳入
    精髓:是在於自動傳值

      1.1綁定對象的方法
        在類內部定義的函數(沒有被任何裝飾器修飾的),默認是綁定給對象用的

      1.2綁定給類的方法
        在類內部定義的函數如果被裝飾器@classmethod裝飾,
        那麽則是綁定給類的,應該由類來調用,類來調用就自動將類當做第一個參數自動傳入

    綁定給類的:自動傳的是類的值
    綁定給對象的:自動傳的是對象的值

  2.非綁定方法

    類中定義的函數如果被裝飾器@staticmethod裝飾,那麽該函數就變成非綁定方法
    既不與類綁定,又不與對象綁定,意味著類與對象都可以來調用
    但是無論誰來調用,都沒有任何自動化傳值的效果,就是一個普通函數

  

  3.應用
    什麽時候綁定給類? 什麽時候綁定給對象?
    取決於函數體代碼
    如果函數體代碼需要用外部傳入的類,則應該將該函數定義成綁定類的方法
    如果函數體代碼需要用外部傳入的對象,則應該將該函數定義成綁定給對象的方法
    如果函數體代碼既不需要外部傳入的類也不需要外部傳入的對象,則應該將該函數定義成非綁定方法對象,則應該將該函數定義成非綁定方法

  

 1 #綁定方法初始實例:綁定給類@classmethod
 2 
 3 class Foo:
 4     @classmethod
 5     def f1(cls):
 6         print(Foo.f1)
 7         print(cls)
 8 
 9     def f2(self):
10         print(self)
11 obj=Foo()
12 # print(obj.f2)   #默認綁定給對象用#<bound method Foo.f2 of <__main__.Foo object at 0x04BACD10>>
13 # print(Foo.f1)   #綁定給類用 <bound method Foo.f1 of <class ‘__main__.Foo‘>>
14 Foo.f1()     #類調用
15 print(Foo)   #所以傳入的值就是類的值 <class ‘__main__.Foo‘>
16 
17 obj.f2()    #對象調用,
18 print(obj)  #所以傳入的值就是對象的值 <__main__.Foo object at 0x04C50EB0>
19 
20 # f1綁定給類的應該由類來調用,但對象其實也可以使用,只不過自動傳入的任然是類
21 #f2綁定給對象的應該由對象來調用,但是類其實也可以使用

 1 # 綁定方法進階實例2:新的實例化方式,綁定給類
 2 """
 3 將需要傳入的信息寫到settings.py文件裏面,調用更加靈活方便
 4 IP=‘192.168.11.3‘
 5 PORT=3306
 6 """
 7 import settings
 8 
 9 class Mysql:
10     def __init__(self,ip,port):
11         self.ip=ip
12         self.port=port
13     def tell_info(self):
14         print(%s:%s%(self.ip,self.port))
15         # print(self)
16 
17     @classmethod
18     def from_conf(cls):
19         return cls(settings.IP,settings.PORT) #可以理解為 Mysql(‘1.1.1.1‘,23)即調用了init方法,給其傳參數 cls名字可以隨便起
20     # print(settings.IP)
21 
22 #默認的實例化方式:類名(..)(實質給tell_info(self)裏的self傳的是對象res的值)
23 res=Mysql(1.1.1.1,23)
24 print(res)  #<__main__.Mysql object at 0x05717410>即為對象res也就是tell_info(self)的值
25 res.tell_info()
26 
27 # 一種新的實例化方式,從配置文件中讀取配置完成實例化(這裏實質給cls傳的是類Mysql的值)
28 res=Mysql.from_conf()
29 res.tell_info()
30 print(res.ip)

非綁定方法應用實例:

 1 #非綁定方法應用實例:uuid獲取隨機id值
 2 
 3 import uuid
 4 class UserInfo:
 5     def __init__(self,name,age):
 6 
 7         self.name=name
 8         self.age=age
 9         self.uid = self.create_uid()
10     def tell_info(self):
11         print(姓名:%s,年齡:%s,ID:%s%(self.name,self.age,self.uid))
12         # print(self)
13 
14     @staticmethod          #因為不需要傳任何參數所以定義為非綁定方法,類和對象都可以取調用
15     def create_uid():
16         return uuid.uuid1()
17 
18 res=UserInfo(張三,23,)
19 res.tell_info()
20 print(res.uid)

Python封裝與隱藏