<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python基礎第十三講: 太好了!最全的Python面向?qū)ο笕腴T教程了,來了!

          共 15947字,需瀏覽 32分鐘

           ·

          2021-04-07 11:48




          作者:浪子燕青       鏈接:

          http://www.langzi.fun/Python面向?qū)ο缶幊?html


          面向?qū)ο缶幊毯秃瘮?shù)式編程(面向過程編程)都是程序設計的方法,不過稍有區(qū)別。

          面向過程編程:

          1. 導入各種外部庫
          2. 設計各種全局變量
          3. 寫一個函數(shù)完成某個功能
          4. 寫一個函數(shù)完成某個功能
          5. 寫一個函數(shù)完成某個功能
          6. 寫一個函數(shù)完成某個功能
          7. 寫一個函數(shù)完成某個功能
          8. ......
          9. 寫一個main函數(shù)作為程序入口

          在多函數(shù)程序中,許多重要的數(shù)據(jù)被放置在全局數(shù)據(jù)區(qū),這樣它們可以被所有的函數(shù)訪問。每個函數(shù)都可以具有它們自己的局部數(shù)據(jù),將某些功能代碼封裝到函數(shù)中,日后便無需重復編寫,僅調(diào)用函數(shù)即可。從代碼的組織形式來看就是根據(jù)業(yè)務邏輯從上到下壘代碼 。

          面向?qū)ο缶幊蹋?/p>

          1. 導入各種外部庫
          2. 設計各種全局變量
          3. 決定你要的類
          4. 給每個類提供完整的一組操作
          5. 明確地使用繼承來表現(xiàn)不同類之間的共同點
          6. 根據(jù)需要,決定是否寫一個main函數(shù)作為程序入口

          面向?qū)ο缶幊讨?,將函?shù)和變量進一步封裝成類,類才是程序的基本元素,它將數(shù)據(jù)和操作緊密地連結在一起,并保護數(shù)據(jù)不會被外界的函數(shù)意外地改變。類和和類的實例(也稱對象)是面向?qū)ο蟮暮诵母拍?,是和面向過程編程、函數(shù)式編程的根本區(qū)別。

          并不是非要用面向?qū)ο缶幊?,要看你的程序怎么設計方便,但是就目前來說,基本上都是在使用面向?qū)ο缶幊獭?/p>

          類的基本用法


          面向?qū)ο笫峭ㄟ^定義class類來定義,這么說面向?qū)ο缶幊叹褪侵皇褂胏lass類,在class類中有封裝,繼承的功能,并且還可以構造要傳入的參數(shù),方便控制。

          案例一

          import sys
          import time
          reload(sys)
          sys.setdefaultencoding('utf-8')

          class studetn:
          # 定義一個類名為studetn
          def __init__(self,idx):
          # 定義初始化構造,這里使用init,還有別的屬性比如reversed,iter之類的
          self.idx=idx
          # 初始化變量,方便繼承
          def runx(self):
          # 定義運行函數(shù),從上面繼承變量
          print self.idx
          # 打印出idx的值,或者做一些別的處理
          time.sleep(1)
          a=studetn('a')
          a.runx()
          # 這是類的調(diào)用,一定要記得類的使用方法,首先傳入?yún)?shù),類賦值給一個變量a
          # 然后調(diào)用這個類下面定義的函數(shù)

          一些專業(yè)術語概念,既然有面向?qū)ο缶幊踢@個高大上的定義了,自然要搭配一些高大上的概念。

          1、類(Class): 用來描述具有相同屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。其中的對象被稱作類的實例。

          2、實例:也稱對象。通過類定義的初始化方法,賦予具體的值,成為一個”有血有肉的實體”。

          3、實例化:創(chuàng)建類的實例的過程或操作。

          4、實例變量:定義在實例中的變量,只作用于當前實例。

          5、類變量:類變量是所有實例公有的變量。類變量定義在類中,但在方法體之外。

          6、數(shù)據(jù)成員:類變量、實例變量、方法、類方法、靜態(tài)方法和屬性等的統(tǒng)稱。

          7、方法:類中定義的函數(shù)。

          8、靜態(tài)方法:不需要實例化就可以由類執(zhí)行的方法

          9、類方法:類方法是將類本身作為對象進行操作的方法。

          10、方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對父類的方法進行改寫,這個過程也稱override。

          11、封裝:將內(nèi)部實現(xiàn)包裹起來,對外透明,提供api接口進行調(diào)用的機制

          12、繼承:即一個派生類(derived class)繼承父類(base class)的變量和方法。

          13、多態(tài):根據(jù)對象類型的不同以不同的方式進行處理。


          類與實例


          # -*- coding: utf-8 -*-
          # @Time : 2018/5/3 0003 17:02
          # @Author : Langzi
          # @Blog : www.langzi.fun
          # @File : 面向?qū)ο?.py
          # @Software: PyCharm
          import sys
          import time
          import requests
          reload(sys)
          sys.setdefaultencoding('utf-8')

          class cc:
          ccc = 'ccc'
          # cc就是類名 如果想要繼承別的類 就class cc(threading) 意思就是從threading繼承
          def __init__(self,a,b,c):
          self.a=a
          self.b=b
          self.c=c
          # 定義構造的過程就是實例化
          def runx(self):
          print self.a*10
          print self.b*5
          print self.c*2
          def runy(self):
          print requests.get('http://www.langzi.fun').headers
          e = cc('AAA','CCC','EEE')
          e.runx()
          e.runy()
          # 這兩個就是調(diào)用類里面的方法
          print e.c
          #實例變量指的是實例本身擁有的變量。每個實例的變量在內(nèi)存中都不一樣。
          print e.ccc
          #類變量,在類里面找到定義的變量。

          調(diào)用類的三種方法

          實例方法


          # -*- coding: utf-8 -*-
          # @Time : 2018/5/3 0003 17:16
          # @Author : Langzi
          # @Blog : www.langzi.fun
          # @File : 面向?qū)ο?.py
          # @Software: PyCharm
          import sys
          import time
          import requests
          reload(sys)
          sys.setdefaultencoding('utf-8')

          class dd:
          def __init__(self,url):
          self.url=url
          def runx(self):
          print requests.get(self.url).status_code

          a = dd('http://www.langzi.fun')
          a.runx()
          # 這種調(diào)用方法就是實例方法

          靜態(tài)方法

          靜態(tài)方法由類調(diào)用,無默認參數(shù)。將實例方法參數(shù)中的self去掉,然后在方法定義上方加上@staticmethod,就成為靜態(tài)方法。它屬于類,和實例無關。建議只使用類名.靜態(tài)方法的調(diào)用方式。(雖然也可以使用實例名.靜態(tài)方法的方式調(diào)用)

          # -*- coding: utf-8 -*-
          # @Time : 2018/5/3 0003 17:21
          # @Author : Langzi
          # @Blog : www.langzi.fun
          # @File : 面向?qū)ο?.py
          # @Software: PyCharm
          import sys
          import requests
          reload(sys)
          sys.setdefaultencoding('utf-8')
          class ff:
          @staticmethod
          def runx():
          print requests.get('http://www.langzi.fun').status_code
          ff.runx()
          #這里就直接調(diào)用了類的變量,只在類中運行而不在實例中運行的方法

          經(jīng)常有一些跟類有關系的功能但在運行時又不需要實例和類參與的情況下需要用到靜態(tài)方法. 比如更改環(huán)境變量或者修改其他類的屬性等能用到靜態(tài)方法. 這種情況可以直接用函數(shù)解決, 但這樣同樣會擴散類內(nèi)部的代碼,造成維護困難。

          類方法

          類方法由類調(diào)用,采用@classmethod裝飾,至少傳入一個cls(代指類本身,類似self)參數(shù)。執(zhí)行類方法時,自動將調(diào)用該方法的類賦值給cls。建議只使用類名.類方法的調(diào)用方式。(雖然也可以使用實例名.類方法的方式調(diào)用)

          實際案例

          如果要構造一個類,接受一個網(wǎng)站和這個網(wǎng)站的狀態(tài)碼,然后打印出來。就像這樣:

          import sys
          import requests
          reload(sys)
          sys.setdefaultencoding('utf-8')
          class gg:
          def __init__(self,url,stat):
          self.url=url
          self.stat=stat
          def outer(self):
          print self.url
          print self.stat
          a = gg('langzi',200)
          a.outer()

          這樣就是使用實例方法,雖然可以實現(xiàn),但是有的時候傳入的參數(shù)并不是(‘langzi’,200)這樣的格式,而是(‘langzi-200’)這樣的,那該怎么做?首先要把這個拆分,但是要使用實例方法實現(xiàn)起來很麻煩,這個時候就可以使用類方法。

          # -*- coding: utf-8 -*-
          # @Time : 2018/5/3 0003 17:27
          # @Author : Langzi
          # @Blog : www.langzi.fun
          # @File : 面向?qū)ο?.py
          # @Software: PyCharm
          import sys
          import requests
          reload(sys)
          sys.setdefaultencoding('utf-8')
          class gg:
          url = 0
          stat = 0
          # 因為使用classmethod后會傳入新的變量,所以一開始是需要自己先定義類變量
          def __init__(self,url=0,stat=0):
          # 這里按照正常的定義構造函數(shù)
          self.url=url
          self.stat=stat
          @classmethod
          # 裝飾器,立馬執(zhí)行下面的函數(shù)
          def split(cls,info):
          # 這個函數(shù)接受兩個參數(shù),默認的cls就是這個類的init函數(shù),info就是外面?zhèn)魅脒M來的
          url,stat=map(str,info.split('-'))
          # 這里轉(zhuǎn)換成了格式化的結構
          data = cls(url,stat)
          # 然后執(zhí)行這個類第一個方法,這個類構造函數(shù)需要傳入兩個參數(shù),于是就傳入了兩個參數(shù)
          return data
          # 這里就直接返回了函數(shù)結果
          def outer(self):
          print self.url
          print self.stat

          r = gg.split(('langzi-200'))
          r.outer()
          # 這里是調(diào)用類方法,與調(diào)用實例方法一樣

          類的特性

          封裝

          封裝是指將數(shù)據(jù)與具體操作的實現(xiàn)代碼放在某個對象內(nèi)部,外部無法訪問。必須要先調(diào)用類的方法才能啟動。

          案例

          class cc:
          ccc = 'ccc'
          # cc就是類名 如果想要繼承別的類 就class cc(threading) 意思就是從threading繼承
          def __init__(self,a,b,c):
          self.a=a
          self.b=b
          self.c=c
          print e.ccc
          #類變量,在類里面找到定義的變量。
          print ccc
          # 這里會報錯,這就是封裝。類中的函數(shù)同理。

          繼承

          當我們定義一個class的時候,可以從某個現(xiàn)有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。
          比如,我們已經(jīng)編寫了一個名為Animal的class,有一個run()方法可以直接打印:

          class Animal(object):
          def run(self):
          print 'Animal is running...'

          當我們需要編寫Dog和Cat類時,就可以直接從Animal類繼承:

          class Dog(Animal):
          pass
          class Cat(Animal):
          pass

          繼承有什么好處?最大的好處是子類獲得了父類的全部功能。由于Animial實現(xiàn)了run()方法,因此,Dog和Cat作為它的子類,什么事也沒干,就自動擁有了run()方法:

          dog = Dog()
          dog.run()
          cat = Cat()
          cat.run()

          當子類和父類都存在相同的run()方法時,我們說,子類的run()覆蓋了父類的run(),在代碼運行的時候,總是會調(diào)用子類的run()。這樣,我們就獲得了繼承的另一個好處:多態(tài)。

          多態(tài)

          要理解多態(tài)的好處,我們還需要再編寫一個函數(shù),這個函數(shù)接受一個Animal類型的變量:

          def run_twice(animal):
          animal.run()
          animal.run()

          當我們傳入Animal的實例時,run_twice()就打印出:

          run_twice(Animal())
          運行結果:
          Animal is running...
          Animal is running...

          當我們傳入Dog的實例時,run_twice()就打印出:

          run_twice(Dog())
          運行結果:
          Dog is running...
          Dog is running...

          當我們傳入Cat的實例時,run_twice()就打印出:

          run_twice(Cat())
          運行結果:
          Cat is running...
          Cat is running...

          看上去沒啥意思,但是仔細想想,現(xiàn)在,如果我們再定義一個Tortoise類型,也從Animal派生:

          class Tortoise(Animal):
          def run(self):
          print 'Tortoise is running slowly...'

          當我們調(diào)用run_twice()時,傳入Tortoise的實例:

          run_twice(Tortoise())
          運行結果:
          Tortoise is running slowly...
          Tortoise is running slowly...


          你會發(fā)現(xiàn),新增一個Animal的子類,不必對run_twice()做任何修改,實際上,任何依賴Animal作為參數(shù)的函數(shù)或者方法都可以不加修改地正常運行,原因就在于多態(tài)。

          多態(tài)的好處就是,當我們需要傳入Dog、Cat、Tortoise……時,我們只需要接收Animal類型就可以了,因為Dog、Cat、Tortoise……都是Animal類型,然后,按照Animal類型進行操作即可。由于Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類或者子類,就會自動調(diào)用實際類型的run()方法,這就是多態(tài)的意思:

          對于一個變量,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調(diào)用run()方法,而具體調(diào)用的run()方法是作用在Animal、Dog、Cat還是Tortoise對象上,由運行時該對象的確切類型決定,這就是多態(tài)真正的威力:調(diào)用方只管調(diào)用,不管細節(jié),而當我們新增一種Animal的子類時,只要確保run()方法編寫正確,不用管原來的代碼是如何調(diào)用的。這就是著名的“開閉”原則:

          • 對擴展開放:允許新增Animal子類;

          • 對修改封閉:不需要修改依賴Animal類型的run_twice()等函數(shù)。


          總結:繼承可以把父類的所有功能都直接拿過來,這樣就不必重零做起,子類只需要新增自己特有的方法,也可以把父類不適合的方法覆蓋重寫;
          有了繼承,才能有多態(tài)。在調(diào)用類實例方法的時候,盡量把變量視作父類類型,這樣,所有子類類型都可以正常被接收;
          舊的方式定義Python類允許不從object類繼承,但這種編程方式已經(jīng)嚴重不推薦使用。任何時候,如果沒有合適的類可以繼承,就繼承自object類。

          魔法方法


          在上面有提到除了__init__之外還有iter,reverse的方法,這里就詳細說下除了init初始化還有哪些別的方法。

          __init__ :      構造函數(shù),在生成對象時調(diào)用
          __del__ : 析構函數(shù),釋放對象時使用
          __repr__ : 打印,轉(zhuǎn)換
          __setitem__ : 按照索引賦值
          __getitem__: 按照索引獲取值
          __len__: 獲得長度
          __cmp__: 比較運算
          __call__: 調(diào)用
          __add__: 加運算
          __sub__: 減運算
          __mul__: 乘運算
          __div__: 除運算
          __mod__: 求余運算
          __pow__: 冪

          具體使用

          1. __doc__


          說明性文檔和信息。Python自建,無需自定義。

          class Foo:
          """ 描述類信息,可被自動收集 """
          def func(self):
          pass
          # 打印類的說明文檔
          print(Foo.__doc__)

          2. __init__()


          實例化方法,通過類創(chuàng)建實例時,自動觸發(fā)執(zhí)行。

          class Foo:
          def __init__(self, name):
          self.name = name
          self.age = 18
          obj = Foo('jack') # 自動執(zhí)行類中的 __init__ 方法

          3. __module__ 和 __class__


          module 表示當前操作的對象在屬于哪個模塊。
          class 表示當前操作的對象屬于哪個類。
          這兩者也是Python內(nèi)建,無需自定義。

          class Foo:
          pass
          obj = Foo()
          print(obj.__module__)
          print(obj.__class__)

          運行結果:
          main


          4. __del__()


          析構方法,當對象在內(nèi)存中被釋放時,自動觸發(fā)此方法。

          注:此方法一般無須自定義,因為Python自帶內(nèi)存分配和釋放機制,除非你需要在釋放的時候指定做一些動作。析構函數(shù)的調(diào)用是由解釋器在進行垃圾回收時自動觸發(fā)執(zhí)行的。

          class Foo:
          def __del__(self):
          print("我被回收了!")

          obj = Foo()
          del obj

          5. __call__()


          如果為一個類編寫了該方法,那么在該類的實例后面加括號,可會調(diào)用這個方法。

          注:構造方法的執(zhí)行是由類加括號執(zhí)行的,即:對象 = 類名(),而對于call() 方法,是由對象后加括號觸發(fā)的,即:對象() 或者 類()()

          class Foo:
          def __init__(self):
          pass
          def __call__(self, *args, **kwargs):
          print('__call__')
          obj = Foo() # 執(zhí)行 __init__
          obj() # 執(zhí)行 __call__

          可以用Python內(nèi)建的callable()函數(shù)進行測試,判斷一個對象是否可以被執(zhí)行。

          callable(Student())

          運行結果:

          True

          6. __dict__


          列出類或?qū)ο笾械乃谐蓡T!非常重要和有用的一個屬性,Python自建,無需用戶自己定義。

          class Province:
          country = 'China'
          def __init__(self, name, count):
          self.name = name
          self.count = count
          def func(self, *args, **kwargs):
          print'func'
          # 獲取類的成員
          print(Province.__dict__)
          # 獲取 對象obj1 的成員
          obj1 = Province('HeBei',10000)
          print(obj1.__dict__)
          # 獲取 對象obj2 的成員
          obj2 = Province('HeNan', 3888)
          print(obj2.__dict__)

          7. __str__()


          如果一個類中定義了str()方法,那么在打印對象時,默認輸出該方法的返回值。這也是一個非常重要的方法,需要用戶自己定義。 

          下面的類,沒有定義str()方法,打印結果是:<main.Foo object at 0x000000000210A358>

          class Foo:
          pass
          obj = Foo()
          print(obj)
          定義了__str__()方法后,打印結果是:'jack'。
          class Foo:
          def __str__(self):
          return 'jack'
          obj = Foo()
          print(obj)

          8、__getitem__()、__setitem__()、__delitem__()


          取值、賦值、刪除這“三劍客”的套路,在Python中,我們已經(jīng)見過很多次了,比如前面的@property裝飾器。

          Python中,標識符后面加圓括號,通常代表執(zhí)行或調(diào)用方法的意思。而在標識符后面加中括號[],通常代表取值的意思。Python設計了getitem()、setitem()、delitem()這三個特殊成員,用于執(zhí)行與中括號有關的動作。它們分別表示取值、賦值、刪除數(shù)據(jù)。

          也就是如下的操作:

          a = 標識符[]?。骸 ?zhí)行__getitem__方法
          標識符[] = a :  執(zhí)行__setitem__方法
          del 標識符[]?。骸 ?zhí)行__delitem__方法

          如果有一個類同時定義了這三個魔法方法,那么這個類的實例的行為看起來就像一個字典一樣,如下例所示:

          class Foo:
          def __getitem__(self, key):
          print('__getitem__',key)
          def __setitem__(self, key, value):
          print('__setitem__',key,value)
          def __delitem__(self, key):
          print('__delitem__',key)
          obj = Foo()
          result = obj['k1'] # 自動觸發(fā)執(zhí)行 __getitem__
          obj['k2'] = 'jack' # 自動觸發(fā)執(zhí)行 __setitem__
          del obj['k1'] # 自動觸發(fā)執(zhí)行 __delitem__

          9. __iter__()


          這是迭代器方法!列表、字典、元組之所以可以進行for循環(huán),是因為其內(nèi)部定義了 iter()這個方法。如果用戶想讓自定義的類的對象可以被迭代,那么就需要在類中定義這個方法,并且讓該方法的返回值是一個可迭代的對象。當在代碼中利用for循環(huán)遍歷對象時,就會調(diào)用類的這個iter()方法。

          普通的類:

          class Foo:
          pass
          obj = Foo()
          for i in obj:
          print(i)
          # 報錯:TypeError: 'Foo' object is not iterable<br># 原因是Foo對象不可迭代
          添加一個__iter__(),但什么都不返回:
          class Foo:
          def __iter__(self):
          pass
          obj = Foo()
          for i in obj:
          print(i)
          # 報錯:TypeError: iter() returned non-iterator of type 'NoneType'
          #原因是 __iter__方法沒有返回一個可迭代的對象

          返回一個個迭代對象:

          class Foo:
          def __init__(self, sq):
          self.sq = sq
          def __iter__(self):
          return iter(self.sq)
          obj = Foo([11,22,33,44])
          for i in obj:
          print(i)

          最好的方法是使用生成器:

          class Foo:
          def __init__(self):
          pass
          def __iter__(self):
          yield 1
          yield 2
          yield 3
          obj = Foo()
          for i in obj:
          print(i)

          10、__len__()


          在Python中,如果你調(diào)用內(nèi)置的len()函數(shù)試圖獲取一個對象的長度,在后臺,其實是去調(diào)用該對象的len()方法,所以,下面的代碼是等價的:

          len('ABC')
          3
          'ABC'.__len__()
          3

          Python的list、dict、str等內(nèi)置數(shù)據(jù)類型都實現(xiàn)了該方法,但是你自定義的類要實現(xiàn)len方法需要好好設計。


          11. __repr__()


          這個方法的作用和str()很像,兩者的區(qū)別是str()返回用戶看到的字符串,而repr()返回程序開發(fā)者看到的字符串,也就是說,repr()是為調(diào)試服務的。通常兩者代碼一樣。

          class Foo:
          def __init__(self, name):
          self.name = name
          def __str__(self):
          return "this is %s" % self.name
          __repr__ = __str__

          12. __add__: 加運算 __sub__: 減運算 __mul__: 乘運算 __div__: 除運算 __mod__: 求余運算 __pow__: 冪運算


          這些都是算術運算方法,需要你自己為類設計具體運算代碼。有些Python內(nèi)置數(shù)據(jù)類型,比如int就帶有這些方法。Python支持運算符的重載,也就是重寫。

          class Vector:
          def __init__(self, a, b):
          self.a = a
          self.b = b
          def __str__(self):
          return 'Vector (%d, %d)' % (self.a, self.b)
          def __add__(self,other):
          return Vector(self.a + other.a, self.b + other.b)
          v1 = Vector(2,10)
          v2 = Vector(5,-2)
          print (v1 + v2)

          13. __author__作者信息


          __author__ = "Jack"
          def show():
          print(__author__)
          show()

          14. __slots__


          Python作為一種動態(tài)語言,可以在類定義完成和實例化后,給類或者對象繼續(xù)添加隨意個數(shù)或者任意類型的變量或方法,這是動態(tài)語言的特性。例如:

          def print_doc(self):
          print("haha")

          class Foo:
          pass

          obj1 = Foo()
          obj2 = Foo()
          # 動態(tài)添加實例變量
          obj1.name = "jack"
          obj2.age = 18
          # 動態(tài)的給類添加實例方法
          Foo.show = print_doc
          obj1.show()
          obj2.show()

          但是!如果我想限制實例可以添加的變量怎么辦?可以使slots限制實例的變量,比如,只允許Foo的實例添加name和age屬性。

          def print_doc(self):
          print("haha")
          class Foo:
          __slots__ = ("name", "age")
          pass
          obj1 = Foo()
          obj2 = Foo()
          # 動態(tài)添加實例變量
          obj1.name = "jack"
          obj2.age = 18
          obj1.sex = "male" # 這一句會彈出錯誤
          # 但是無法限制給類添加方法
          Foo.show = print_doc
          obj1.show()
          obj2.show()
          由于'sex'不在__slots__的列表中,所以不能綁定sex屬性,試圖綁定sex將得到AttributeError的錯誤。
          Traceback (most recent call last):
          File "F:/Python/pycharm/201705/1.py", line 14, in <module>
          obj1.sex = "male"
          AttributeError: 'Foo' object has no attribute 'sex'

          需要提醒的是,slots定義的屬性僅對當前類的實例起作用,對繼承了它的子類是不起作用的。想想也是這個道理,如果你繼承一個父類,卻莫名其妙發(fā)現(xiàn)有些變量無法定義,那不是大問題么?如果非要子類也被限制,除非在子類中也定義slots,這樣,子類實例允許定義的屬性就是自身的slots加上父類的slots。


          成員保護與訪問機制


          有些對象你不想外部訪問,即使是通過調(diào)用類對象也無法訪問,那就請認真學完本章節(jié)。

          私有成員

          class obj:
          def __init__(self,name):
          self.name=name
          def pri(self):
          print self.name
          __age = 18
          # 加上雙下劃線的就是私有變量,只能在類的內(nèi)部訪問,外部無法訪問
          a = obj('zhao')
          a.pri()

          運行結果:

          zhao

          如果要在類中調(diào)用這個私有成員,可以這么用

          class obj:
          def __init__(self,name):
          self.name=name
          def prin(self):
          print self.name
          __age = 18
          # 加上雙下劃線的就是私有變量,只能在類的內(nèi)部訪問,外部無法訪問
          @classmethod
          # 如果要在類中調(diào)用,首先調(diào)用類方法
          def pri(cls):
          print cls.__age
          # 然后在使用
          a = obj('zhao')
          a.prin()
          obj.pri()
          # 通過這樣直接調(diào)用類中的私有變量

          運行結果:

          zhao
          18

          使用get-set-del方法操作私有成員

          class obj:
          def __init__(self,name):
          self.name=name
          def prin(self):
          print self.name
          __age = 18
          # 加上雙下劃線的就是私有變量,只能在類的內(nèi)部訪問,外部無法訪問
          @classmethod
          # 如果要在類中調(diào)用,首先調(diào)用類方法
          def pri(cls):
          print cls.__age
          # 然后在使用
          @classmethod
          def set_age(cls,value):
          cls.__age = value
          return cls.__age
          # 這個用法就是改變__age的值
          @classmethod
          def get_age(cls):
          return cls.__age
          # 這個用法就是直接返回__age的值
          @classmethod
          def del_age(cls):
          del cls.__age
          # 這個用法就是直接刪除__age的值

          print obj.get_age()
          # 這里是直接調(diào)用出__age的值 返回值18
          print obj.set_age(20)
          # 這里是直接改變__age的值 返回值20
          obj.del_age()
          # 這里是直接刪除__age的值

          思考:既然是私有變量,不讓外部訪問,為何有要在后面調(diào)用又改變呢?因為可以對私有變量進行額外的檢測,處理,加工等等。比如判斷value的值,使用isinstance然后做if-else判斷。

          使用私有變量可以對內(nèi)部變量進行保護,外部無法改變,但是可以對它進行檢測處理。

          這里引申一下私有成員的保護機制,使用__age對私有變量其實就是—>obj._obj__age的樣子進行保護,說白了你直接使用obj._obj__age就可以直接調(diào)用內(nèi)部私有變量age了。

          Propety裝飾器


          把類的方法偽裝成屬性調(diào)用的方式,就是把類里面的一個函數(shù),變成一個屬性一樣的東西~
          一開始調(diào)用類的方法要使用圓括號,現(xiàn)在變成了屬性進行讀取設置存儲。
          舉個例子來說明:

          常用的調(diào)用方法

          class obj:
          def __init__(self,name,age):
          self.__name=name
          self.__age=age
          # 講這些設置成私有變量
          def get_age(self):
          return self.__age
          def set_age(self,value):
          if isinstance(value,int):
          self.__age=value
          else:
          raise ValueError('非整數(shù)類型')
          def del_age(self):
          print 'delete over'
          a = obj('langzi',18)
          print a.get_age()
          a.set_age(20)
          print a.get_age()

          使用裝飾器

          class obj:
          def __init__(self,name,age):
          self.__name=name
          self.__age=age
          # 把這些設置成私有變量
          @property
          def age(self):
          return self.__age
          @age.setter
          def age(self,value):
          if isinstance(value,int):
          self.__age=value
          else:
          raise ValueError('非整數(shù)類型')
          @age.deleter
          def age(self):
          print 'delete over'
          a = obj('langzi',18)
          # 使用這些裝飾器,可以使用類與對象的方法直接調(diào)用
          print a.age
          # 這里就是直接調(diào)用返回age的值
          a.age=20
          # 這里就是直接使用setter把值轉(zhuǎn)換
          print a.age
          del a.age
          # 刪除age

          當然這種調(diào)用方法有些麻煩,每次都是一個一個去實例類與對象,有個更加簡單直觀的方法。

          更加減半的使用property()函數(shù)

          除了使用裝飾器的方式將一個方法偽裝成屬性外,Python內(nèi)置的builtins模塊中的property()函數(shù),為我們提供了第二種設置類屬性的手段。

          class People:

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

          def get_age(self):
          return self.__age

          def set_age(self, age):
          if isinstance(age, int):
          self.__age = age
          else:
          raise ValueError

          def del_age(self):
          print("刪除年齡數(shù)據(jù)!")

          # 核心在這句
          age = property(get_age, set_age, del_age, "年齡")

          obj = People("jack", 18)
          print(obj.age)
          obj.age = 19
          print("obj.age: ", obj.age)
          del obj.ag

          通過語句age = property(get_age, set_age, del_age, “年齡”)將一個方法偽裝成為屬性。其效果和裝飾器的方法是一樣的。

          property()函數(shù)的參數(shù):

          第一個參數(shù)是方法名,調(diào)用 實例.屬性 時自動執(zhí)行的方法
          第二個參數(shù)是方法名,調(diào)用 實例.屬性 = XXX時自動執(zhí)行的方法
          第三個參數(shù)是方法名,調(diào)用 del實例.屬性 時自動執(zhí)行的方法
          第四個參數(shù)是字符串,調(diào)用 實例.屬性.__doc__時的描述信息。

          (完)

          零基礎學 Python,看下嘛
          送109元的零基礎視頻課

           只需7天時間,跨進Python編程大門,已有3800+加入
          【基礎】0基礎入門python,24小時有人快速解答問題;
          【提高】40多個項目實戰(zhàn),老手可以從真實場景中學習python;
          【直播】不定期直播項目案例講解,手把手教你如何分析項目;
          【分享】優(yōu)質(zhì)python學習資料分享,讓你在最短時間獲得有價值的學習資源;圈友優(yōu)質(zhì)資料或?qū)W習分享,會不時給予贊賞支持,希望每個優(yōu)質(zhì)圈友既能賺回加入費用,也能快速成長,并享受分享與幫助他人的樂趣。
          【人脈】收獲一群志同道合的朋友,并且都是python從業(yè)者
          【價格】本著布道思想,只需 69元 加入一個能保證學習效果的良心圈子。
          【贈予】價值109元 0基礎入門在線課程,免費送給圈友們,供鞏固
          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  男女暧暧操逼网站视频 | 国产黄片免费视频 | 亚洲国产成人精品女人久久久 | 天天抽天天操 | 在线观看国产成人AV一天堂 |