本節內容:html
見概述:http://www.cnblogs.com/linhaifeng/articles/6428835.htmlpython
面向過程的程序設計的核心是過程,過程即解決問題的步驟,面向過程的設計就比如精心設計好一條流水線,考慮周全何時處理什麼東西。linux
優勢是:極大的下降了程序的複雜度c++
缺點是:一套流水線或者流程就是用來解決一個問題,生產汽水的流水線沒法生產汽車,即使是能,也得是大改,改一個組件,牽一髮而動全身。git
應用場景:一旦完成基本不多改變的場景,著名的例子有Linux內核,git,以及Apache HTTP Server等。算法
面向對象的程序設計的核心是對象,要理解對象爲什麼物,必須把本身當成上帝,上帝眼裏世間存在的萬物皆爲對象,不存在的也能夠創造出來。面向對象的程序設計比如如來設計西遊記,如來要解決的問題是把經書傳給東土大唐,如來想了想解決這個問題須要四我的:唐僧,沙和尚,豬八戒,孫悟空,每一個人都有各自的特徵和技能(這就是對象的概念,特徵和技能分別對應對象的數據屬性和方法屬性),然而這並很差玩,因而如來又安排了一羣妖魔鬼怪,爲了防止師徒四人在取經路上被搞死,又安排了一羣神仙保駕護航,這些都是對象。而後取經開始,師徒四人與妖魔鬼怪神仙交互着直到最後取得真經。如來根本不會管師徒四人按照什麼流程去取。編程
面向對象的程序設計的app
優勢是:解決了程序的擴展性。對某一個對象單獨修改,會馬上反映到整個體系中,如對遊戲中一我的物參數的特徵和技能修改都很容易。編程語言
缺點:可控性差,沒法向面向過程的程序設計流水線式的能夠很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題,即使是上帝也沒法預測最終結果。因而咱們常常看到一個遊戲人某一參數的修改極有可能致使陰霸的技能出現,一刀砍死3我的,這個遊戲就失去平衡。ide
應用場景:需求常常變化的軟件,通常需求的變化都集中在用戶層,互聯網應用,企業內部軟件,遊戲等都是面向對象的程序設計大顯身手的好地方
面向對象的程序設計並非所有。對於一個軟件質量來講,面向對象的程序設計只是用來解決擴展性。
python中一切皆爲對象,且python3統一了類與類型的概念,類型就是類,因此,無論你信不信,你已經使用了很長時間的類了
>>> dict #類型dict就是類dict <class 'dict'> >>> d=dict(name='lijun') #實例化 >>> d {'name': 'lijun'} >>> d.pop('name') #向d發一條消息,執行d的方法pop,至關於調用dict類的一個屬性,其中pop這個函數就是刪除字典的指定內容而且回顯 'lijun'
基於面向對象設計一個款遊戲:英雄聯盟,每一個玩家選一個英雄,每一個英雄都有本身的特徵和和技能,特徵即數據屬性,技能即方法屬性,特徵與技能的結合體就一個對象。
從一組對象中提取類似的部分就是類,類也是特徵與技能的結合體,特徵即數據而且是全部對象共享的數據,技能即函數屬性而且是全部對象共享的函數屬性。
garen_hero.Q()稱爲向garen_hero這個對象發送了一條消息,讓他去執行Q這個函數,完成一個功能,相似的有:
garen_hero.W()
garen_hero.E()
garen_hero.R()
一個英雄能夠攻擊另一個英雄,這就是對象之間的交互
garen_hero.attack(Riven)
#類有兩個功能:實例化和屬性引用 class Garen: #lol遊戲人物蓋倫 camp='Demacia' #陣營:德瑪西亞 def __init__(self,nickname,aggresivity,life_value): #每一個玩家都有共同的屬性:名字,攻擊力,生命值 self.nickname = nickname self.aggresivity = aggresivity self.life_value = life_value def attack(self,enemy): #定義一個攻擊的屬性 print('is attacking....',self,enemy) #類的第一個功能:實例化 g1 = Garen('草叢倫',82,100) #實例化,至關於生成一個遊戲玩家 g2 = Garen('hahaha',12,1020) #類的第二個功能:屬性引用,包含數據屬性和函數屬性 print(Garen.camp) print(Garen.__init__) print(Garen.attack) #對於一個實例來講,只有一種功能:屬性引用 print(g1.nickname,g1.aggresivity,g1.life_value) # print(g1.attack,id(g1.attack)) #經過實例來調用類中的函數,根據顯示的內容就是綁定方法 print(Garen.attack,id(Garen.attack)) #經過類來調用本身的函數屬性 #總結: #對於類來講就是數據(camp)和函數(attack)的結合體 #對於類的數據屬性來講,共享給因此實例 #對於類的函數來講,綁定給實例用,綁定了就是爲了給實例用的,實例能夠傳本身的參數 Garen.attack(1,2) g1.attack('lijun') #至關於:Garen.attack(g1,'lijun') 這就是綁定方法的牛逼用處,自動傳值 print(g1.camp,id(g1.camp)) print(g2.camp,id(g2.camp)) print(Garen.camp,id(Garen.camp))
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ # #類體現出對象與對象交互的概念 class Garen: #lol遊戲人物蓋倫 camp='Demacia' #陣營:德瑪西亞 def __init__(self,nickname,aggresivity,life_value): #每一個玩家都有共同的屬性:名字,攻擊力,生命值 self.nickname = nickname self.aggresivity = aggresivity self.life_value = life_value def attack(self,enemy): #定義一個攻擊的屬性 print('is attacking....',self,enemy) class Riven: camp='Noxus' def __init__(self, nickname, aggresivity, life_value): # 每一個玩家都有共同的屬性:名字,攻擊力,生命值 self.nickname = nickname self.aggresivity = aggresivity self.life_value = life_value def attack(self, enemy): # 定義一個攻擊的屬性 print('is attacking....', self, enemy) enemy.life_value -= self.aggresivity #g1的最後生命值就是g1如今的生命值減去r1的攻擊力 g1 = Garen('草叢倫',82,100) r1 = Riven('hahah',20,1000) #模擬riven英雄攻擊garen英雄 r1.attack(g1) print(g1.life_value) #因此最後g1的生命值就是100-20
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ # #寫一個類的過程:舉列,女媧造人 #第一步:先想下人(實例)有什麼通用的屬性,私有的屬性,共同的技能,先站住實例的角度去想 #第二步:寫的時候在開始寫class,而後在生成實例 class Chinese: dang = 'gongchandang' #通用的屬性 def __init__(self,name,age,gender): #私有的屬性 self.name = name self.age = age self.gender = gender def talk(self): print('chifan shuijiao dadoudou......') #共同的技能 d=Chinese('lijun',18,'F')
查找方法:
在obj.name會先從obj本身的名稱空間(__init__)裏找name,找不到則去類中找,類也找不到就找父類...最後都找不到就拋出異常
4.1什麼是繼承
繼承是一種建立新的類的方式,在python中,新建的類能夠繼承自一個或者多個父類,原始類稱爲基類或超類,新建的類稱爲派生類或子類。
python中類的繼承分爲:單繼承和多繼承
class ParentClass1: #定義父類 pass class ParentClass2: #定義父類 pass class SubClass1(ParentClass1): #單繼承,基類是ParentClass1,派生是指subclass1類裏本身獨有的功能 pass class SubClass2(ParentClass1,ParentClass2): #python支持多繼承,用逗號分隔開多個繼承的類 pass
查看繼承
>>> SubClass1.__bases__ (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
提示:若是沒有指定基類,python的類會默認繼承object類,object是全部python類的基類,它提供了一些常見方法(如__str__)的實現。
只要繼承爲object,就被稱爲新式類
>>> ParentClass1.__bases__ (<class 'object'>,) >>> ParentClass2.__bases__ (<class 'object'>,)
4.2 繼承與抽象
抽象即抽取相似或者說比較像的部分。
抽象分紅兩個層次:
1.將奧巴馬和梅西這倆對象比較像的部分抽取成類;
2.將人,豬,狗這三個類比較像的部分抽取成父類。
抽象最主要的做用是劃分類別(能夠隔離關注點,下降複雜度)
繼承:是基於抽象的結果,經過編程語言去實現它,確定是先經歷抽象這個過程,才能經過繼承的方式去表達出抽象的結構。
抽象只是分析和設計的過程當中,一個動做或者說一種技巧,經過抽象能夠獲得類
4.3 繼承的重要性
在開發程序的過程當中,若是咱們定義了一個類A,而後又想新創建另一個類B,可是類B的大部份內容與類A的相同時
咱們不可能從頭開始寫一個類B,這就用到了類的繼承的概念。
經過繼承的方式新建類B,讓B繼承A,B會‘遺傳’A的全部屬性(數據屬性和函數屬性),實現代碼重用
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ class Hero: def __init__(self,nickname,aggresivity,life_value): #每一個玩家都有共同的屬性:名字,攻擊力,生命值 self.nickname = nickname self.aggresivity = aggresivity self.life_value = life_value def attack(self,enemy): #定義一個攻擊的屬性 print('is attacking....',self,enemy) enemy.life_value -= self.aggresivity class Garen(Hero): camp='Demacia' def fly(self): #蓋倫本身的功能,會飛 print('is frying......') def attack(self): print('這個優先') class Riven(Hero): camp='Noxus' g1 = Garen('草叢倫',82,100) g1.fly() g1.attack() #假如重名會先到本身類裏面找,找不到在去找父類
4.4 組合與重用性
組合指的是,在一個類中以另一個類的對象做爲數據屬性,稱爲類的組合
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #組合 #幾個類之間沒有共同之處,在一個類中以另一個類的對象做爲數據屬性 class Teacher: def __init__(self,name): self.name = name self.birth = Date(1994,8,18) self.course = Course('python','11000','5mons') class Course: def __init__(self,name,price,period): self.name = name self.price = price self.period = period class Date: def __init__(self,year,month,day): self.year = year self.month = month self.day = day t1 = Teacher('alex') print(t1.birth.year) #假如只調用出生的年
4.5 接口與歸一化設計
繼承有兩種用途:
一:繼承基類的方法,而且作出本身的改變或者擴展(代碼重用)
二:聲明某個子類兼容於某基類,定義一個接口類Interface,接口類中定義了一些接口名(就是函數名)且並未實現接口的功能,子類繼承接口類,而且實現接口中的功能
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #運用場景:你去駕校考駕照,學會了就能夠開寶馬,開奧迪,學會了一種方法,其餘的就都會了 #案例:inux一切皆文件 class AllFile: #接口類,接口類只定義要有什麼功能,不去真實的實現 def read(self): #接口函數 pass def write(self): pass class Text(AllFile): def read(self): print('文件的讀功能!') def write(self): print('文件的寫功能!') class Sata(AllFile): def read(self): print('sata的讀功能!') def write(self): print('sata的寫功能!') t=Text() s=Sata()
爲何要用接口:(這是一種設計思路)
接口提取了一羣類共同的函數,能夠把接口當作一個函數的集合。
而後讓子類去實現接口中的函數。
這麼作的意義在於歸一化,什麼叫歸一化,就是隻要是基於同一個接口實現的類,那麼全部的這些類產生的對象在使用時,從用法上來講都同樣。
歸一化,讓使用者無需關心對象的類是什麼,只須要的知道這些對象都具有某些功能就能夠了,這極大地下降了使用者的使用難度。
好比:咱們定義一個動物接口,接口裏定義了有跑、吃、呼吸等接口函數,這樣老鼠的類去實現了該接口,松鼠的類也去實現了該接口,由兩者分別產生一隻老鼠和一隻松鼠送到你面前,即使是你分別不到底哪隻是什麼鼠你確定知道他倆都會跑,都會吃,都能呼吸。
再好比:咱們有一個汽車接口,裏面定義了汽車全部的功能,而後由本田汽車的類,奧迪汽車的類,大衆汽車的類,他們都實現了汽車接口,這樣就好辦了,你們只須要學會了怎麼開汽車,那麼不管是本田,仍是奧迪,仍是大衆咱們都會開了,開的時候根本無需關心我開的是哪一類車,操做手法(函數調用)都同樣
4.6 抽象類和接口
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ # # #剛纔的那個接口例子,子類不寫具體實現的功能也是能夠的 # class AllFile: #接口類,接口類只定義要有什麼功能,不去真實的實現 # def read(self): #接口函數 # pass # # def write(self): # pass # # class Text(AllFile): # pass # # # # t=Text() #假如我想控制子類必需要實現功能,必須重寫read和write的函數,不然就報錯 #這種方法就叫作抽象類 #概念:抽象類只是用來繼承的,繼承的人負責實現父類的功能 import abc class AllFile(metaclass=abc.ABCMeta): #抽象類 @abc.abstractclassmethod def read(self): pass @abc.abstractclassmethod def write(self): pass class Text(AllFile): def read(self): pass def write(self): pass t=Text()
4.7 繼承順序
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__) #只有新式纔有這個屬性能夠查看線性列表,經典類沒有這個屬性 #新式類繼承順序:F->D->B->E->C->A #經典類繼承順序:F->D->B->A->E->C #python3中統一都是新式類 #pyhon2中才分新式類與經典類
繼承原理:
python究竟是如何實現繼承的,對於你定義的每個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的全部基類的線性順序列表,例如
>>> F.mro() #等同於F.__mro__ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
爲了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類爲止。
而這個MRO列表的構造是經過一個C3線性化算法來實現的。咱們不去深究這個算法的數學原理,它實際上就是合併全部父類的MRO列表並遵循以下三條準則:
1.子類會先於父類被檢查
2.多個父類會根據它們在列表中的順序被檢查
4.8 子類調用父類的方法
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #假如子類想要調用父類中的test功能 # # class A: # def test(self): # print('from a.test') # # class B(A): # def test(self): # A.test(self) # print('from b.test') # # b1=B() # b1.test() #運用場景 class People: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def test(self): print('from a.test') class Teacher(People): def __init__(self,name,age,gender,level): # People.__init__(self,name,age,gender) super().__init__(name,age,gender) self.level = level t = Teacher('lijun',18,'female','高級講師') print(t.level)
多態性的好處:
1.增長了程序的靈活性
以不變應萬變,不論對象變幻無窮,使用者都是同一種形式去調用,如func(animal)
2.增長了程序額可擴展性
經過繼承animal類建立了一個新的類,使用者無需更改本身的代碼,仍是用func(animal)去調用
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #多態指的是一類事物有多種形態,(一個抽象類有多個子類,於是多態的概念依賴於繼承) class Animal: def talk(self): pass class People(Animal): def talk(self): print('say hello') class Pig(Animal): def talk(self): print('say ao ao ao') class Dog(Animal): def talk(self): print('say wang wang wang') p1=People() pig=Pig() d1=Dog() #如下就是多態性,牛逼之處,假如在來個貓的類,下面的函數無需更改,直接傳值 def func(obj): obj.talk() func(p1) func(pig) func(d1)
6.1 封裝要裝什麼
你錢包的有多少錢(數據的封裝)
你的性取向(數據的封裝)
你撒尿的具體功能是怎麼實現的(方法的封裝)
6.2 爲何要用封裝
封裝數據的主要緣由是:保護隱私(做爲男人的你,臉上就寫着:我喜歡男人,你懼怕麼?)
封裝方法的主要緣由是:隔離複雜度(快門就是傻瓜相機爲傻瓜們提供的方法,該方法將內部複雜的照相功能都隱藏起來了,好比你沒必要知道你本身的尿是怎麼流出來的,你直接掏出本身的接口就能用尿這個功能)
你的身體沒有一處不體現着封裝的概念:你的身體把膀胱尿道等等這些尿的功能隱藏了起來,而後爲你提供一個尿的接口就能夠了(接口就是你的。。。,),你總不能把膀胱掛在身體外面,上廁所的時候就跟別人炫耀:hi,man,你瞅個人膀胱,看看我是怎麼尿的。還有你的頭把你的腦子封裝到了腦袋裏,而後提供了眼睛這個接口....
提示:在編程語言裏,對外提供的接口(接口可理解爲了一個入口),就是函數,稱爲接口函數,這與接口的概念還不同,接口表明一組接口函數的集合體。
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #封裝有兩個層面 #第一個層面:假入從另一個腳本執行這個函數,經過導入模塊的方式,對於用戶來講這個函數是看不出來是怎麼寫的,直接調用就行了 # class Foo: # x=1 # def __init__(self,name): # self.name = name #第二個層面:self.__money class Foo: x=1 def __init__(self,name,money): self.name = name self.__money = money #實際就是變造成了_Foo__money def tell_info(self): print(self.__money) #在內部能夠調用外部不能調用, def __spam(self): print('testtesttest') f = Foo('alex',2000000000) #print(f.__money) #若直接調用封裝了的money的參數會報錯 #print(f.__dict__) #用__dict__能夠具體查看變了形的結果,其實類就是將裏面的數據變成了字典的形式(經過.來從字典裏獲取數據)。 f.tell_info() #這時就能夠調用money的函數了 print(f.__dict__) #對比實例和類的字典 print(Foo.__dict__)
插一嘴,類在定義的時候會執行一遍類裏的內容,變形只會在定義的時候發生一次,之後都不會變形了。
class Foo: print('》》》》》》》》》》') def __init__(self,name,money): self.name = name self.__money = money #實際就是變造成了_Foo__money f = Foo('alex',2000000000) print(f.__dict__) f.__x = 1 #新加一個變量 print(f.__dict__) print(f.__x) #而後就能夠調用了
6.3 特性protected
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #property做用就是將類的函數轉換成類的屬性,實例調用的時候就當作屬性來用 #注意:property場景不能穿參數 # # import math # class Circle: # def __init__(self,radius): #圓的半徑radius # self.radius=radius # # @property # def area(self): # return math.pi * self.radius**2 #計算面積 # # @property # def perimeter(self): # return 2*math.pi*self.radius #計算周長 # # c=Circle(10) # print(c.radius) # print(c.area) #能夠向訪問數據屬性同樣去訪問area,會觸發一個函數的執行,動態計算出一個值 # print(c.perimeter) #同上 import math class Circle: def __init__(self,radius): self.radius =radius def area(self): return math.pi * self.radius**2 def perimeter(self): return 2*math.pi*self.radius area = property(area) perimeter = property(perimeter) c = Circle(10) #若想要計算員的周長和麪積,對於使用者來講,必須調用兩個函數 #print(c.area()) #print(c.perimeter()) #可是用了priperty後,就至關於將函數變成了變量,轉換成了數據屬性,對於使用者來講就是數據屬性 print(c.area) print(c.perimeter)
爲何用protected?
將一個類的函數定義成特性之後,對象再去使用的時候obj.name,根本沒法察覺本身的name是執行了一個函數而後計算出來的,這種特性的使用方式遵循了統一訪問的原則
python並無在語法上把它們三個內建到本身的class機制中,在C++裏通常會將全部的全部的數據都設置爲私有的,而後提供set和get方法(接口)去設置和獲取,在python中經過property方法能夠實現
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ # # class A: # def __init__(self,name): # self.__name = name # # @property #相似c++ get功能 # def name(self): # return self.__name # # @name.setter #相似C++ set功能 # def name(self,value): # self.__name=value # # @name.deleter # def name(self): # print('------') # # a=A('lijun') # print(a.name) # # a.name=2 # print(a.name) # # del a.name #用處:假如我穿個參數,a.name = 111,可是個人姓名必須是字符串,增長了對屬性操做的靈活性 class A: def __init__(self,name): self.__name = name @property #相似c++ get功能 def name(self): return self.__name @name.setter #相似C++ set功能 def name(self,value): if not isinstance(value,str): #假如不是字符串我就拋出個異常 raise TypeError('%s must be str' %value) self.__name=value @name.deleter def name(self): #不讓刪除的提示 print('------') raise AttributeError(' bu neng shan chu ') a=A('lijun') print(a.name) # a.name=111111 # print(a.name) del a.name
一般狀況下,在類中定義的全部函數(注意了,這裏說的就是全部,跟self啥的不要緊,self也只是一個再普通不過的參數而已)都是對象的綁定方法,對象在調用綁定方法時會自動將本身做爲參數傳遞給方法的第一個參數。除此以外還有兩種常見的方法:靜態方法和類方法,兩者是爲類量身定製的,可是實例非要使用,也不會報錯,後續將介紹。
7.1 靜態方法
是一種普通函數,位於類定義的命名空間中,不會對任何實例類型進行操做,python爲咱們內置了函數staticmethod來把類中的函數定義成靜態方法
class Foo: def spam(x,y,z): #類中的一個函數,千萬不要懵逼,self和x啥的沒有不一樣都是參數名 print(x,y,z) spam=staticmethod(spam) #把spam函數作成靜態方法
基於以前所學裝飾器的知識,@staticmethod 等同於spam=staticmethod(spam),因而
class Foo: @staticmethod #裝飾器 def spam(x,y,z): print(x,y,z)
使用演示
print(type(Foo.spam)) #類型本質就是函數 Foo.spam(1,2,3) #調用函數應該有幾個參數就傳幾個參數 f1=Foo() f1.spam(3,3,3) #實例也可使用,但一般靜態方法都是給類用的,實例在使用時喪失了自動傳值的機制 ''' <class 'function'> 1 2 3 3 3 3 '''
應用場景:
import time class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day @staticmethod def now(): #用Date.now()的形式去產生實例,該實例用的是當前時間 t=time.localtime() #獲取結構化的時間格式 return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建實例而且返回 @staticmethod def tomorrow():#用Date.tomorrow()的形式去產生實例,該實例用的是明天的時間 t=time.localtime(time.time()+86400) return Date(t.tm_year,t.tm_mon,t.tm_mday) a=Date('1987',11,27) #本身定義時間 b=Date.now() #採用當前時間 c=Date.tomorrow() #採用明天的時間 print(a.year,a.month,a.day) print(b.year,b.month,b.day) print(c.year,c.month,c.day)
7.2 類方法
類方法是給類用的,類在使用時會將類自己當作參數傳給類方法的第一個參數,python爲咱們內置了函數classmethod來把類中的函數定義成類方法
#類方法 # class A: # x=1 # @classmethod # def test(cls): # print(cls,cls.x) #cls就是類A # # A.test() #補充 # class A: # def __init__(self,name): # self.name = name # # def __str__(self): # return '%s' %self.name # # a=A('lijun') # print(a) #若是不定義__str__內置函數,那麼打印的是a的內存地址 #類方法的應用場景,相比靜態方法,比較靈活 import time class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day @classmethod def now(cls): t=time.localtime() return cls(t.tm_year,t.tm_mon,t.tm_mday) d1=Date.now() print(d1.year,d1.month,d1.day)
兩種類的區別和用處:
import time class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day @staticmethod def now(): t=time.localtime() return Date(t.tm_year,t.tm_mon,t.tm_mday) class EuroDate(Date): def __str__(self): return 'year:%s month:%s day:%s' %(self.year,self.month,self.day) e=EuroDate.now() print(e) #咱們的意圖是想觸發EuroDate.__str__,可是結果爲 ''' 輸出結果: <__main__.Date object at 0x1013f9d68> '''
由於e就是用Date類產生的,因此根本不會觸發EuroDate.__str__,解決方法就是用classmethod
import time class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day # @staticmethod # def now(): # t=time.localtime() # return Date(t.tm_year,t.tm_mon,t.tm_mday) @classmethod #改爲類方法 def now(cls): t=time.localtime() return cls(t.tm_year,t.tm_mon,t.tm_mday) #哪一個類來調用,即用哪一個類cls來實例化 class EuroDate(Date): def __str__(self): return 'year:%s month:%s day:%s' %(self.year,self.month,self.day) e=EuroDate.now() print(e) #咱們的意圖是想觸發EuroDate.__str__,此時e就是由EuroDate產生的,因此會如咱們所願 ''' 輸出結果: year:2017 month:3 day:3 '''
強調,注意注意注意:靜態方法和類方法雖然是給類準備的,可是若是實例去用,也是能夠用的,只不過實例去調用的時候容易讓人混淆,不知道你要幹啥
x=e.now() #經過實例e去調用類方法也同樣可使用,靜態方法也同樣 print(x) ''' 輸出結果: year:2017 month:3 day:3 '''
http://www.cnblogs.com/linhaifeng/articles/6182264.html#_label27
hasattr(容器,‘名稱’) #以字符串的形式判斷某個對象中是否含有指定的屬性
getattr(容器,‘名稱’) #以字符串的形式去某個對象中獲取指定的屬性
setattr(容器,‘名稱’,值) #以字符串的形式去某個對象中設置指定的屬性
delattr(容器,‘名稱’) #以字符串的形式去某個對象中刪除指定的屬性
案例1:當前目錄下有個test目錄,test目錄下有個account的模塊,輸入不一樣的路徑,執行不一樣的結果,可是個人這些功能都在統一的目錄下
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #案例:假若有一個網站,輸入不一樣的路徑,執行不一樣的結果,可是個人這些功能都在統一的目錄下 #用戶輸入:account/login acccount/logout li = ['account/login','acccount/logout'] inp = input('》》》') m,n = inp.split('/') import sys,os sys.path.append(r'D:\pycharm\s16\day7\反射\test') import account if inp in li: if n == "login": res = account.login() elif n == 'logout': res = account.logout() else: print('沒有這個功能。。。') print(res)
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ def login(): return '請輸入用戶名和密碼' def logout(): return '跳轉頁面'
案例2:以上的方法用反射來實現,getattr()
#反射:getattr() 專門去某個地方獲取他的內部的東西,PS:獲取的東西是字符串的形式 #用反射去實現以上的內容 import sys,os sys.path.append(r'D:\pycharm\s16\day7\反射\test') import account # v=getattr(account,'login') # print(v) action = input('>>') v = getattr(account,action) result = v() print(result)
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ def login(): return '請輸入用戶名和密碼' def logout(): return '跳轉頁面'
C:\Python35\python3.exe D:/pycharm/s16/day7/反射/反射.py >>login 請輸入用戶名和密碼
案例3:hasattr()函數的用法,先判斷我這個模塊裏有沒有函數,有的話就執行,沒有就報404
#反射:hasattr() 專門去某個地方獲取他的內部的東西,PS:獲取的東西是字符串的形式 import sys,os sys.path.append(r'D:\pycharm\s16\day7\反射\test') import account action = input('>>') # a = hasattr(account,action) # print(a) #假如account文件裏有action那麼就輸出True不然false if(hasattr(account,action)): func = getattr(account,action) result = func() else: result = '404' print(result)
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ def login(): return '請輸入用戶名和密碼' def logout(): return '跳轉頁面'
C:\Python35\python3.exe D:/pycharm/s16/day7/反射/反射.py >>aaa 404 C:\Python35\python3.exe D:/pycharm/s16/day7/反射/反射.py >>logout 跳轉頁面
案例4:
#setattr和delattr的用法 import sys,os sys.path.append(r'D:\pycharm\s16\day7\反射\test') import account h = hasattr(account,'findpwd') print(h) setattr(account,'findpwd',lambda x:x+1) #增長findpwd函數 h = hasattr(account,'findpwd') #這時值就爲True print(h) delattr(account,'findpwd') #刪除 h = hasattr(account,'findpwd') print(h)
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ def login(): return '請輸入用戶名和密碼' def logout(): return '跳轉頁面'
C:\Python35\python3.exe D:/pycharm/s16/day7/反射/反射.py
False
True
False
案例5:深刻運用,假如同一個目錄下有好的功能存在不一樣的模塊中(環境是在包中演示)
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #以字符串的形式導入模塊 #import time #v = __import__('time') while True: # account/login # home/index inp=input('請輸入url:') m,n = inp.split('/') module = __import__('controller.%s' %m,fromlist=True) # print(module) if hasattr(module,n): func = getattr(module,n) result = func() else: print('404') print(result)
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ def login(): print('longin......') return 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' def logout(): print('longout......') return 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ def index(): print('aaaaaa') return '這個是index函數' print('honme..........')
C:\Python35\python3.exe D:/pycharm/s16/day7/反射_package/反射.py 請輸入url:home/index honme.......... aaaaaa 這個是index函數 請輸入url:account/login longin...... aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 請輸入url:account/laaaaaaaaaaaaaaaaaaaaaaaaa 404 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 請輸入url:
案例6:繼續優化腳本,假如輸入沒有的模塊,也報錯,可是程序不退出
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ #以字符串的形式導入模塊 #import time #v = __import__('time') while True: # account/login # home/index inp=input('請輸入url:') m,n = inp.split('/') try: #假如導入沒有的模塊,就報401 module = __import__('controller.%s' %m,fromlist=True) # print(module) if hasattr(module,n): func = getattr(module,n) result = func() else: print('404') except Exception as e: result = 401 print(result)
C:\Python35\python3.exe D:/pycharm/s16/day7/反射_package/反射.py 請輸入url:sss/sssss 401 請輸入url:
1.__doc__ 表示類的描述信息
class Foo: """ 描述類信息,這是用於看片的神奇 """ def func(self): pass print(Foo.__doc__) # 輸出: 描述類信息,這是用於看片的神奇
2.__module__ 和 __class__
__module__ 表示當前操做的對象在那個模塊
__class__ 表示當前操做的對象的類是什麼
class C: def __init__(self): self.name = 'wupeiqi'
from lib.aaa import C obj = C() print(obj.__module__) # 輸出 lib.aaa,即:輸出模塊,字符串的形式 print(obj.__class__ ) # 輸出 lib.aa.C,即:輸出類
3. __call__ 對象後面加括號,觸發執行。
注:構造方法的執行是由建立對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print '__call__' obj = Foo() # 執行 __init__ obj() # 執行 __call__
4. __new__ \ __metaclass__
class Foo(object): def __init__(self, name): self.name = name f = Foo("alex") print(type(f)) # 輸出:<class '__main__.Foo'> 表示,obj 對象由Foo類建立 print(type(Foo)) # 輸出:<type 'type'> 表示,Foo類對象都是由 type 類建立
上述代碼中,obj 是經過 Foo 類實例化的對象,其實,不只 obj 是一個對象,Foo類自己也是一個對象,由於在Python中一切事物都是對象。
若是按照一切事物都是對象的理論:obj對象是經過執行Foo類的構造方法建立,那麼Foo類對象應該也是經過執行某個類的 構造方法 建立。
因此,f對象是Foo類的一個實例,Foo類對象是 type 類的一個實例,即:Foo類對象 是經過type類的構造方法建立。
那麼,建立類就能夠有兩種方式:
a)普通方式:
class Foo(object): def sayhi(self,name): print('hello ', name)
b)特殊方式:
def sayhi(self,name): print('hello ',name) f= type('Foo', (object,), {'func': sayhi}) # type第一個參數:類名 # type第二個參數:當前類的基類 # type第三個參數:類的成員 # # 上面f=的格式就和普通格式同樣 print(f) print(type(f)) print(dir(f)) #查看類名下有哪些函數 #f.func('ddd') #若想要使用sayhi的函數 f_obj=f() #實例化 f_obj.func('lijun') #調用函數
def func(self): print("hello %s"%self.name) def __init__(self,name,age): self.name = name self.age = age Foo = type('Foo',(object,),{'func':func,'__init__':__init__}) f = Foo("jack",22) f.func()
# -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ # class Foo(object): # def __init__(self, name): # self.name = name # print('Foo __init__') # # def __new__(cls, *args, **kwargs): #init的觸發都是由new來實現的,原來默認裏有個new,你在寫new方法會頂替 # print('Foo __new__') # # f = Foo("alex") #這時實例化後顯示的不是'Foo __initclass Foo(object): #利用new方法實現調用init #new只是生成了一塊內存空間,並無賦值,交給init賦值 class Foo(object): def __init__(self, name): self.name = name print('Foo __init__') def __new__(cls, *args, **kwargs): #整個類的實例化其實都是經過new來實現的 print('Foo __new__') obj = object.__new__(cls) print('obj:::',obj) return obj f = Foo("alex") print(f.name)
1 class MyType(type): 2 def __init__(self,*args,**kwargs): 3 4 print("Mytype __init__",*args,**kwargs) 5 6 def __call__(self, *args, **kwargs): 7 print("Mytype __call__", *args, **kwargs) 8 obj = self.__new__(self) 9 print("obj ",obj,*args, **kwargs) 10 print(self) 11 self.__init__(obj,*args, **kwargs) 12 return obj 13 14 def __new__(cls, *args, **kwargs): 15 print("Mytype __new__",*args,**kwargs) 16 return type.__new__(cls, *args, **kwargs) 17 18 print('here...') 19 class Foo(object,metaclass=MyType): 20 21 22 def __init__(self,name): 23 self.name = name 24 25 print("Foo __init__") 26 27 def __new__(cls, *args, **kwargs): 28 print("Foo __new__",cls, *args, **kwargs) 29 return object.__new__(cls) 30 31 f = Foo("Alex") 32 print("f",f) 33 print("fname",f.name)
動態導入模塊
import importlib __import__('import_lib.metaclass') #這是解釋器本身內部用的 #importlib.import_module('import_lib.metaclass') #與上面這句效果同樣,官方建議用這個
http://www.cnblogs.com/wupeiqi/articles/5017742.html
1.異常基礎
案例1:最簡單的語法,假如一個程序出錯了,不是立馬就報錯退出程序,下面的程序還會執行
#打印一個不存在的變量 try: print(name) except NameError as e: print(e) print('keep going.....') #輸出 name 'name' is not defined #抓到的錯誤信息 keep going.....
2.異常種類
python中的異常種類很是多,每一個異常專門用於處理某一項異常!!!
AttributeError 試圖訪問一個對象沒有的樹形,好比foo.x,可是foo沒有屬性x IOError 輸入/輸出異常;基本上是沒法打開文件 ImportError 沒法引入模塊或包;基本上是路徑問題或名稱錯誤 IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊 IndexError 下標索引超出序列邊界,好比當x只有三個元素,卻試圖訪問x[5] KeyError 試圖訪問字典裏不存在的鍵 KeyboardInterrupt Ctrl+C被按下 NameError 使用一個還未被賦予對象的變量 SyntaxError Python代碼非法,代碼不能編譯(我的認爲這是語法錯誤,寫錯了) TypeError 傳入對象類型與要求的不符合 UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是因爲另有一個同名的全局變量, 致使你覺得正在訪問它 ValueError 傳入一個調用者不指望的值,即便值的類型是正確的
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
names = ['a','b'] try: print(name) #走到這裏就報錯了,下面的就不執行了,直接跳到except print(names[3]) except NameError as e: print(e) print('keep going.....')
#能夠抓到其中一個錯誤,可是不能同時抓住 names = ['a','b'] try: print(names[3]) print(name) except NameError as e: print(e) except IndexError as e: print(e) print('keep going.....')
#能夠抓到其中一個錯誤,可是不能同時抓住 names = ['a','b'] try: print(names[3]) print(name) except (NameError,IndexError) as e: print(e) except IndexError as e: print(e) print('keep going.....')
備註:IndentationError和SyntaxError的錯誤信息是抓不到的,由於解釋器根本就執行不了這兩類的代碼。
#Exception萬能異常,通常不用,不方便調試 names = ['a','b'] try: print(names[3]) print(name) except Exception as e: print(e) print('keep going.....')
#else的用法 names = ['a','b'] try: print(names[1]) # print(name) except IndexError as e: print(e) except Exception as e: print(e) else: print('什麼錯都沒有,就會執行')
#finally的用法 names = ['a','b'] try: print(names[1]) print(name) except IndexError as e: print(e) except Exception as e: print(e) else: print('什麼錯都沒有,就會執行') finally: print('不管有沒有錯都執行')
3.自定義異常
class WupeiqiException(Exception): def __init__(self, msg): self.message = msg def __str__(self): return self.message try: raise WupeiqiException('個人異常') except WupeiqiException,e: print e
4.斷言
# assert 條件 assert 1 == 1 assert 1 == 2