日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第七章 再谈抽象

發布時間:2023/12/1 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第七章 再谈抽象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第七章 再談抽象

對象魔法

多態:可對不同類型的對象執行相同的操作,而這些操作就像“被施了魔法”一樣能夠正常運行。(即:無需知道對象的內部細節就可使用它)(無需知道對象所屬的類(對象的類型)就能調用其方法
封裝:對外部隱藏有關對象工作原理的細節。(無需知道對象的構造就能使用它
繼承:可基于通用類創建出專用類。

1,多態

即便你不知道變量指向的是哪種對象,也能夠對其執行操作,且操作的行為將隨對象所屬的類型(類)而異。

2,多態和方法

與對象屬性相關聯的函數稱為方法
如果有一個變量x,你無需知道它是字符串還是列表就能調用方法count:只要你向這個方法提供一個字符作為參數,它就能正常運行。count方法返回指定字符串出現的個數。

'abc'.count('a')#結果為:1 ['a',1, 2, 'a','a'].count('a')#結果為:3

標準庫模塊random包含一個名為choice的函數,它從序列中隨機選擇一個元素。

from random import choice x = choice(['Hello, world!', [1, 2, 'e', 'e', 4]])#x可能包含字符串'Hello, world!',也可能包含列表[1, 2, 'e', 'e', 4] x.count('e')#可能是1,也可能是2

多態形式多樣。每當無需知道對象是什么樣的就能對其執行操作時,都是多態在起作用。這不僅僅適用于方法,還可以通過內置運算符和函數使用多態。

參數可以是任何支持加法的對象
加法運算符(+)既可用于數(這里是整數),也可用于字符串(以及其他類型的序列)

1 + 2#結果為:3 'beyond' + 'huangjiaju'#結果為:'beyondhuangjiaju'

等價于下面函數:

def add(x, y): return x + yadd(1,2)#結果為:3 add('beyond','huangjiaju')#結果為:'beyondhuangjiaju'

編寫一個函數,通過打印一條消息來指出對象的長度

def length_message(x): print("The length of", repr(x), "is", len(x))length_message('beyond')#結果為:The length of 'beyond' is 6 length_message([1, 2, 3])#結果為:The length of [1, 2, 3] is 3

要破壞多態,唯一的辦法是使用諸如type、issubclass等函數顯式地執行類型檢查,但你應盡可能避免以這種方式破壞多態。

3,封裝

封裝(encapsulation)指的是向外部隱藏不必要的細節
屬性是歸屬于對象的變量,就像方法一樣。
對象有自己的狀態。對象的狀態由其屬性(如名稱)描述。
對象的方法可能修改這些屬性,因此對象將一系列函數(方法)組合起來,并賦予它們訪問一些變量(屬性)的權限,而屬性可用于在兩次函數調用之間存儲值。
多態讓你無需知道對象所屬的類(對象的類型)就能調用其方法
而封裝讓你無需知道對象的構造就能使用它。

4,繼承

繼承是另一種偷懶的方式。
如果你已經有了一個類,并要創建一個與之很像的類(可能只是新增了幾個方法),可以讓創建的這個類去繼承已有的類。

類到底是什么?

類的定義——一種對象。
每個對象都屬于特定的類,并被稱為該類的實例。
對于類的名稱,在Python中,約定使用單數并將首字母大寫,如Bird和Lark。
類是由其支持的方法定義的,類的所有實例都有該類的所有方法,因此子類的所有實例都有超類的所有方法。

創建自定義類

對huangjiaju調用set_name和greet時,huangjiaju都會作為第一個參數自動傳遞給它們,這就是self。
self很有用,甚至必不可少。如果沒有它,所有的方法都無法訪問對象本身——要操作的屬性所屬的對象

class Band: def set_name(self, name): self.name = name def get_name(self): return self.name def greet(self): print("Hello! {} band.".format(self.name))huangjiaju = Band() bar = Band() huangjiaju.set_name('Beyond') bar.set_name('The Beatles')huangjiaju.greet()#結果為:Hello! Beyond band. bar.greet()#結果為:Hello! The Beatles band.huangjiaju.name#結果為:'Beyond'bar.name = 'The Rolling Stones' bar.greet()#結果為:Hello! The Rolling Stones band.

屬性、函數和方法

方法和函數的區別表現在于參數self。
方法(更準確地說是關聯的方法)將其第一個參數關聯到它所屬的實例,因此無需提供這個參數。

class Class:def method(self):print("I like beyond band!")def function():print("huangjiaju")instance = Class() instance.method()#結果為:I like beyond band!instance.method = function instance.method()#結果為:huangjiaju

有沒有參數self并不取決于是否以剛才使用的方式(如instance.method)調用方法。

當然,也完全可以讓另一個變量指向同一個方法。

class Band:songer = "huangjiaju"def sing(self):print(self.songer)beyond = Band() beyond.sing()#結果為:huangjiajubeyondsonger = beyond.sing beyondsonger()#結果為:huangjiaju

私有屬性不能從對象外部訪問,而只能通過存取器方法(如get_name和set_name)來訪問。
Python沒有為私有屬性提供直接的支持,而要讓方法或屬性成為私有的(不能從外部訪問),只需讓其名稱以兩個下劃線打頭即可。

class Band:def __huangjiaju(self):print("beyond can't see")def huangjiaqiang(self):print("beyond can see")self.__huangjiaju()yy = Band() yy.__huangjiaju()#報錯!!!yy.huangjiaqiang()#結果為: ''' beyond can see beyond can't see '''

從外部不能訪問__huangjiaju,但在類中(如huangjiaqiang中)依然可以使用它。
以兩個下劃線打頭,這樣的方法類似于其他語言中的標準私有方法。
在類定義中,對所有以兩個下劃線打頭的名稱都進行轉換,即在開頭加上一個下劃線和類名。

class Band:def __huangjiaju(self):print("beyond can't see")def huangjiaqiang(self):print("beyond can see")self.__huangjiaju()yy = Band() yy._Band__huangjiaju()#結果為:beyond can't see

類的命名空間

以下兩條語句大致等價:它們都創建一個返回參數平方的函數

def Hjj(x):return x*xHjq = lambda x:x*xHjj(8)#結果為:64 Hjq(9)#結果為:81

在class語句中定義的代碼都是在一個特殊的命名空間(類的命名空間)內執行的,而類的所有成員都可訪問這個命名空間。

class NumberCounter:number = 0def init(self):NumberCounter.number += 1m1 = NumberCounter() m1.init() NumberCounter.number#結果為:1m2 = NumberCounter() m2.init() NumberCounter.number#結果為:2 ''' 上述代碼在類作用域內定義了一個變量,所有的成員(實例)都可訪問它, 這里使用它來計算類實例的數量,注意到這里使用了init來初始化所有實例!!! '''#每個實例都可訪問這個類作用域內的變量,就像方法一樣 m1.number#結果為:1 m2.number#結果為:2#在一個實例中給屬性number賦值 m1.number = "yy" m1.number#結果為:'yy' m2.number#結果為:2 #新值被寫入m1的一個屬性中,這個屬性遮住了類級變量。

指定超類

子類擴展了超類的定義,要指定超類,可在class語句中的類名后加上超類名,并將其用圓括號括起。

class Filter:def init(self):self.blocked = []def filter(self,sequence):return [x for x in sequence if x not in self.blocked]class SPAMFilter(Filter):#SPAMFilter是Filter的子類def init(self): #重寫超類Filter的方法initself.blocked = ['SPAM']#Filter是一個過濾序列的通用類。實際上,它不會過濾掉任何東西。 f = Filter() f.init() f.filter([1,2,3])#結果為:[1, 2, 3]#Filter類的用途在于可用作其他類(如將'SPAM'從序列中過濾掉的SPAMFilter類)的基類(超類)。 s = SPAMFilter() s.init() s.filter(['SPAM','SPAM','SPAM','SPAM','beyond','huangjiaju','SPAM'])#結果為:['beyond', 'huangjiaju']

請注意SPAMFilter類的定義中有兩個要點。
Ⅰ以提供新定義的方式重寫了Filter類中方法init的定義
Ⅱ直接從Filter類繼承了方法filter的定義,因此無需重新編寫其定義

深入探討繼承

要確定一個類是否是另一個類的子類,可使用內置方法issubclass。
如果你有一個類,并想知道它的基類,可訪問其特殊屬性__bases__。
要確定對象是否是特定類的實例,可使用isinstance。
要獲悉對象屬于哪個類,可使用屬性__class__,還可使用type(s)來獲悉其所屬的類。

class Filter:def init(self):self.blocked = []def filter(self,sequence):return [x for x in sequence if x not in self.blocked]class SPAMFilter(Filter):#SPAMFilter是Filter的子類def init(self): #重寫超類Filter的方法initself.blocked = ['SPAM']issubclass(SPAMFilter, Filter)#結果為:True issubclass(Filter, SPAMFilter)#結果為:FalseSPAMFilter.__bases__#結果為:(__main__.Filter,) Filter.__bases__#結果為:(object,)s = SPAMFilter() isinstance(s,SPAMFilter)#結果為:True isinstance(s,Filter)#結果為:True isinstance(s,str)#結果為:Falses.__class__#結果為:__main__.SPAMFilter type(s)#結果為:__main__.SPAMFilter

多個超類

子類TalkingCalculator本身無所作為,其所有的行為都是從超類那里繼承的。關鍵是通過從Calculator那里繼承calculate,并從Talker那里繼承talk。這被稱為多重繼承,是一個功能強大的工具。除非萬不得已,否則應避免使用多重繼承,因為在有些情況下,它可能帶來意外的“并發癥”。

class Calculator:def calulate(self,expression):self.value = eval(expression)class Talker:def talk(self):print('Hi,my value is',self.value)class TalkingCalulator(Calculator,Talker):passyy = TalkingCalulator() yy.calulate('5+2+1*1314') yy.talk()#結果為:Hi,my value is 1321

多個超類的超類相同時,查找特定方法或屬性時訪問超類的順序稱為方法解析順序(MRO),它使用的算法非常復雜。

接口和內省

接口這一概念與多態相關。處理多態對象時,你只關心其接口(協議)——對外暴露的方法和屬性
檢查所需的方法是否存在hasattr(對象名,方法名)
檢查屬性是否是可調用的 callable(getattr(對象名, '方法名', None))
getattr(它讓我能夠指定屬性不存在時使用的默認值,這里為None),然后對返回的對象調用callable
setattr與getattr功能相反,可用于設置對象的屬性
要查看對象中存儲的所有值,可檢查其__dict__屬性

class Calculator:def calulate(self,expression):self.value = eval(expression)class Talker:def talk(self):print('Hi,my value is',self.value)class TalkingCalulator(Calculator,Talker):passyy = TalkingCalulator() yy.calulate('5+2+1*1314') yy.talk()#結果為:Hi,my value is 1321hasattr(yy, 'talk')#結果為:True hasattr(yy, 'hahaha')#結果為:Falsecallable(getattr(yy, 'talk', None))#結果為:True callable(getattr(yy, 'hahah', None))#結果為:Falsesetattr(yy, 'name', 'huangjiaju') yy.name#結果為:'huangjiaju'yy.__dict__#結果為:{'name': 'huangjiaju', 'value': 1321}

抽象基類

Python幾乎都只依賴于鴨子類型,即假設所有對象都能完成其工作,同時偶爾使用hasattr來檢查所需的方法是否存在。
很多其他語言(如Java和Go)都采用顯式指定接口的理念,而有些第三方模塊提供了這種理念的各種實現。

Python通過引入模塊abc提供了官方解決方案。這個模塊為所謂的抽象基類提供了支持。標準庫(如模塊collections.abc)提供了多個很有用的抽象類,有關模塊abc的詳細信息。
抽象類是不能(至少是不應該)實例化的類,其職責是定義子類應實現的一組抽象方法。

from abc import ABC,abstractmethod class Talker(ABC):#形如@this的東西被稱為裝飾器@abstractmethod#使用@abstractmethod來將方法標記為抽象的——在子類中必須實現的方法。def talk(self):pass'''抽象類(即包含抽象方法的類)最重要的特征是不能實例化''' Talker()#報錯!!!''' 從它派生出一個子類,由于沒有重寫方法talk,因此這個類也是抽象的,不能實例化。 現在實例化它沒有任何問題。這是抽象基類的主要用途,而且只有在這種情形下使用isinstance才是妥當的: 如果先檢查給定的實例確實是Talker對象,就能相信這個實例在需要的情況下有方法talk。 ''' class Knigger(Talker):def talk(self):print("Ni!")k = Knigger() isinstance(k,Talker)#結果為:True k.talk()#結果為:Ni!''' 然而,還缺少一個重要的部分——讓isinstance的多態程度更高的部分。 來創建另一個類,這個類的實例能夠通過是否為Talker對象的檢查,可它并不是Talker對象。 可從Talker派生出Herring,但Herring可能是從他人的模塊中導入的。 在這種情況下,就無法采取這樣的做法。 ''' class Herring:def talk(self):print("beyond.")h = Herring() isinstance(h,Talker)#結果為:False''' 可將Herring注冊為Talker(而不從Herring和Talker派生出子類), 這樣所有的Herring對象都將被視為Talker對象。 ''' Talker.register(Herring)#結果為:__main__.Herring isinstance(h,Talker)#結果為:True issubclass(Herring,Talker)#結果為:True#上述做法存在一個缺點,就是直接從抽象類派生提供的保障沒有了。class Clam:passTalker.register(Clam)#結果為:__main__.Clamissubclass(Clam,Talker)#結果為:Truec = Clam() isinstance(c,Talker)#結果為:Truec.talk()#報錯!!! #Clam有成為Talker的意圖,相信它能承擔Talker的職責,但可悲的是它失敗了。

關于面向對象設計的一些思考

將相關的東西放在一起。如果一個函數操作一個全局變量,最好將它們作為一個類的屬性和方法。
不要讓對象之間過于親密。方法應只關心其所屬實例的屬性,對于其他實例的狀態,讓它們自己去管理就好了。
慎用繼承,尤其是多重繼承。繼承有時很有用,但在有些情況下可能帶來不必要的復雜性。要正確地使用多重繼承很難,要排除其中的bug更難。
保持簡單。讓方法短小緊湊。一般而言,應確保大多數方法都能在30秒內讀完并理解。對于其余的方法,盡可能將其篇幅控制在一頁或一屏內。

小結

概念解釋
對象對象由屬性和方法組成。屬性不過是屬于對象的變量,而方法是存儲在屬性中的函數。相比于其他函數,(關聯的)方法有一個不同之處,那就是它總是將其所屬的對象作為第一個參數,而這個參數通常被命名為self。
類表示一組(或一類)對象,而每個對象都屬于特定的類。類的主要任務是定義其實例將包含的方法。
多態多態指的是能夠同樣地對待不同類型和類的對象,即無需知道對象屬于哪個類就可調用其方法。
封裝對象可能隱藏(封裝)其內部狀態。在有些語言中,這意味著對象的狀態(屬性)只能通過其方法來訪問。在Python中,所有的屬性都是公有的,但直接訪問對象的狀態時程序員應謹慎行事,因為這可能在不經意間導致狀態不一致。
繼承一個類可以是一個或多個類的子類,在這種情況下,子類將繼承超類的所有方法。你可指定多個超類,通過這樣做可組合正交(獨立且不相關)的功能。為此,一種常見的做法是使用一個核心超類以及一個或多個混合超類。
接口和內省一般而言,你無需過于深入地研究對象,而只依賴于多態來調用所需的方法。然而,如果要確定對象包含哪些方法或屬性,有一些函數可供你用來完成這種工作。
抽象基類使用模塊abc可創建抽象基類。抽象基類用于指定子類必須提供哪些功能,卻不實現這些功能。
面向對象設計關于該如何進行面向對象設計以及是否該采用面向對象設計,有很多不同的觀點。無論你持什么樣的觀點,都必須深入理解問題,進而創建出易于理解的設計。

本章節介紹的新函數

函數描述
callable(object)判斷對象是否是可調用的(如是否是函數或方法)
getattr(object,name[,default])獲取屬性的值,還可提供默認值
hasattr(object, name)確定對象是否有指定的屬性
isinstance(object, class)確定對象是否是指定類的實例
issubclass(A, B)確定A是否是B的子類
random.choice(sequence)從一個非空序列中隨機地選擇一個元素
setattr(object, name, value)將對象的指定屬性設置為指定的值
type(object)返回對象的類型

總結

以上是生活随笔為你收集整理的第七章 再谈抽象的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产中文字幕乱人伦在线观看 | 俺也去综合 | aaa色| 国产成人无遮挡在线视频 | 亚洲男人天堂网站 | 欧美乱妇高清无乱码 | 男人天堂网在线 | 国产在线一区二区视频 | 福利小视频| 国产人与zoxxxx另类 | 调教亲女小嫩苞h文小说 | 国产中文在线视频 | 久久精品一区二区在线观看 | 国产视频在线观看网站 | 黄色岛国片 | 黄色一级视频免费观看 | 国产精品二区三区 | 国产精品人人做人人爽 | 欧美成人秋霞久久aa片 | 亚洲黄色a级片 | 免费在线看黄的网站 | 麻豆电影网站 | 成人av一区二区在线观看 | 8x8ⅹ国产精品一区二区二区 | 麻豆最新网址 | 日韩三级国产精品 | ,国产精品国产三级国产 | 免费一区 | 天天干天天爽天天操 | 久草视频福利在线 | 无码av免费毛片一区二区 | 粉嫩av懂色av蜜臀av分享 | 红桃成人在线 | 美女黄视频网站 | 欧美日韩免费观看视频 | 香蕉成人在线视频 | 婷婷丁香社区 | 久久短视频 | 天天噜夜夜噜 | 国产一区二区三区四区hd | 欧亚av| 久久久国产打桩机 | 美女张开双腿让男人捅 | 国产网址 | 亚洲欧美综合精品久久成人 | 日韩精品一区二区三区免费视频 | 日韩手机在线视频 | 欧美一区二区三区啪啪 | 欧美日韩精品一区二区 | 欧美精品在线一区二区 | 日本三级视频 | 日本孰妇毛茸茸xxxx | 日本变态折磨凌虐bdsm在线 | 天堂av资源在线 | 狠狠操导航 | 91偷拍一区二区三区精品 | 伊人久久五月天 | 朝鲜女人性猛交 | 热久久中文字幕 | 国产字幕在线观看 | 日韩欧美卡一卡二 | av网站大全免费 | 人人澡人人澡人人 | 91成人在线免费视频 | 东南亚毛片 | 蜜桃av鲁一鲁一鲁一鲁俄罗斯的 | 爱如潮水3免费观看日本高清 | 999久久久精品视频 亚洲视频精品在线 | 日本精品在线播放 | 国产色av | 久久久全国免费视频 | 饥渴丰满的少妇喷潮 | 18被视频免费观看视频 | av福利在线 | 国产精品免费久久 | 久草精品在线观看视频 | youjizz日本人 | 杨贵妃颤抖双乳呻吟求欢小说 | 亚洲黄片一区 | 黄网站免费在线观看 | 深夜在线免费视频 | 污网站在线播放 | 精品少妇视频 | 欧洲三级在线 | 免费在线看黄色片 | 色噜噜狠狠一区二区三区果冻 | 俺去草| 国产一级片免费在线观看 | wwwxxx在线| 69久久成人精品 | 日韩av在线看 | 香蕉国产在线 | 中文字幕一区在线观看 | 操网 | 汗汗视频 | 色婷婷亚洲综合 | 久久精品视频16 | 日批视频免费在线观看 | 日韩av中文在线 |