本章內容:python
建立類和對象 |
面向對象編程是一種編程方式,此編程方式的落地須要使用 「類」 和 「對象」 來實現,因此,面向對象編程其實就是對 「類」 和 「對象」 的使用。程序員
類就是一個模板,模板裏能夠包含多個函數,函數裏實現一些功能編程
對象則是根據模板建立的實例,經過實例對象能夠執行類中的函數併發
# 建立類 class Foo: def buy(self): print("This is buy.") def Hello(self, name): print("This is hello.") # 根據類Foo建立對象obj obj = Foo() obj.buy() #執行Bar方法 obj.Hello('nick') #執行Hello方法
類和對象在內存中是如何保存的?ide
類以及類中的方法在內存中只有一份,而根據類建立的每個對象都在內存中須要存一份,大體以下圖:模塊化
如上圖所示,根據類建立對象時,對象中除了封裝 name 和 age 的值以外,還會保存一個類對象指針,該值指向當前對象的類。函數式編程
當經過 obj1 執行方法時,過程以下:函數
注:Java和C#來講只支持面向對象編程,而python比較靈活即支持面向對象編程也支持函數式編程fetch
面向對象三大特性 |
面向對象的三大特性是指:封裝、繼承和多態。url
1、封裝
封裝,顧名思義就是將內容封裝到某個地方,之後再去調用被封裝在某處的內容。
因此,在使用面向對象的封裝特性時,須要:
一、將內容封裝到某處
self 是一個形式參數,當執行 obj = Foo('nick', 18 ) 時,self 等於 obj
當執行 obj2 = Foo('jenny', 21 ) 時,self 等於 obj2
二、從某處調用被封裝的內容
調用被封裝的內容時,有兩種狀況:
class Foo: def __init__(self, name, age): self.name = name self.age = age obj = Foo('nick', 18) print obj.name # 直接調用obj對象的name屬性 print obj.age # 直接調用obj對象的age屬性 obj2 = Foo('jenny', 21) print obj2.name # 直接調用obj2對象的name屬性 print obj2.age # 直接調用obj2對象的age屬性
class Foo: def __init__(self, name, age): self.name = name self.age = age def detail(self): print self.name print self.age obj = Foo('nick', 18) obj.detail() # Python默認會將obj傳給self參數,即:obj.detail(obj),因此,此時方法內部的 self = obj,即:self.name 是 nick ;self.age 是 18 obj2 = Foo('jenny', 21) obj2.detail() # Python默認會將obj2傳給self參數,即:obj1.detail(obj2),因此,此時方法內部的 self = obj2,即:self.name 是 jenny ; self.age 是 21
#封裝 #非主流方式 class Foo: def fetch(self): print(self.nick) def add(self): print(self.jenny) obj = Foo() obj.nick = "Nick_cool" obj.fetch() # obj2 = Foo() obj.nick = "Nick_cool_2" obj.fetch() obj1 = Foo() obj1.jenny = "Jenny_nice" obj1.add() #封裝 class Foo: def __init__(self,bk): """ 構造方法 """ #析構方法在垃圾回收是解釋器本身調用 self.name = bk self.job = "pythoner" # obj.job = "pythoner" self.age = 18 # obj.age = 18 def fetch(self): print(self.name) print(self.age) print(self.job) obj = Foo("nick") obj.fetch()
綜上所述,對於面向對象的封裝來講,其實就是使用構造方法將內容封裝到 對象 中,而後經過對象直接或者self間接獲取被封裝的內容。
2、繼承
對於面向對象的繼承來講,其實就是將多個類共有的方法提取到父類中,子類僅需繼承父類而沒必要一一實現每一個方法。
注:除了子類和父類的稱謂,你可能看到過 派生類 和 基類 ,他們與子類和父類只是叫法不一樣而已。
# 繼承 # 基類 class Animals: def __init__(self,name): self.name = name def eat(self): print(self.name,"吃") # 派生類 class dog(Animals): def tell(self): print("汪星人") dog = dog("啊黃") dog.tell() dog.eat()
繼承 __init__
派生類默認不繼承基類__init__,須要用super聲明
class A: def __init__(self): self.name = "nick" class B(A): def __init__(self): self.age = 18 super(B, self).__init__() #super首先找到B的父類A,而後把類B的對象self轉換爲類A的對象,而後「被轉換」的類A對象調用本身的__init__函數 # A.__init__(self) #指定運行A中__init__,不推薦 obj = B() print(obj.__dict__)
多繼承:
Python的類能夠繼承多個類,Java和C#中則只能繼承一個類
Python3的類繼承多個類的尋找方法的方式,Python 3中沒有經典類、新式類之分
# 多繼承 class A: def f1(self): print("A") class B(A): def f(self): print("B") class C(A): def f(self): print("C") class D(B): def f(self): print("D") class E(C): def f1(self): print("E") class F(D,E): def f(self): print("F") f1 = F() f1.f1()
Python2的類若是繼承了多個類,那麼其尋找方法的方式有兩種,分別是:深度優先和廣度優先
經典類和新式類,從字面上能夠看出一個老一個新,新的必然包含了跟多的功能,也是以後推薦的寫法,從寫法上區分的話,若是 當前類或者父類繼承了object類,那麼該類即是新式類,不然即是經典類。
class D: def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): def bar(self): print 'B.bar' class A(B, C): def bar(self): print 'A.bar' a = A() # 執行bar方法時 # 首先去A類中查找,若是A類中沒有,則繼續去B類中找,若是B類中麼有,則繼續去D類中找,若是D類中麼有,則繼續去C類中找,若是仍是未找到,則報錯 # 因此,查找順序:A --> B --> D --> C # 在上述查找bar方法的過程當中,一旦找到,則尋找過程當即中斷,便不會再繼續找了 a.bar()
class D(object): def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): def bar(self): print 'B.bar' class A(B, C): def bar(self): print 'A.bar' a = A() # 執行bar方法時 # 首先去A類中查找,若是A類中沒有,則繼續去B類中找,若是B類中麼有,則繼續去C類中找,若是C類中麼有,則繼續去D類中找,若是仍是未找到,則報錯 # 因此,查找順序:A --> B --> C --> D # 在上述查找bar方法的過程當中,一旦找到,則尋找過程當即中斷,便不會再繼續找了 a.bar()
經典類:首先去A類中查找,若是A類中沒有,則繼續去B類中找,若是B類中麼有,則繼續去D類中找,若是D類中麼有,則繼續去C類中找,若是仍是未找到,則報錯
新式類:首先去A類中查找,若是A類中沒有,則繼續去B類中找,若是B類中麼有,則繼續去C類中找,若是C類中麼有,則繼續去D類中找,若是仍是未找到,則報錯
注意:在上述查找過程當中,一旦找到,則尋找過程當即中斷,便不會再繼續找了
函數方法裏調用函數方法執行順序
# 函數方法裏調用函數方法執行順序 class D: def buy(self): self.f1() #調用 f1() def f1(self): print("This is D f1.") class C(D): def f1(self): print("This is C f1.") class B: def f1(self): print("This is B f1.") class A(B, C): pass obj = A() obj.buy()
3、多態
class F1: pass class S1(F1): def show(self): print 'S1.show' class S2(F1): def show(self): print 'S2.show' # 因爲在Java或C#中定義函數參數時,必須指定參數的類型 # 爲了讓Func函數既能夠執行S1對象的show方法,又能夠執行S2對象的show方法,因此,定義了一個S1和S2類的父類 # 而實際傳入的參數是:S1對象和S2對象 def Func(F1 obj): """Func函數須要接收一個F1類型或者F1子類的類型""" print obj.show() s1_obj = S1() Func(s1_obj) # 在Func函數中傳入S1類的對象 s1_obj,執行 S1 的show方法,結果:S1.show s2_obj = S2() Func(s2_obj) # 在Func函數中傳入Ss類的對象 ss_obj,執行 Ss 的show方法,結果:S2.show
class F1: pass class S1(F1): def show(self): print 'S1.show' class S2(F1): def show(self): print 'S2.show' def Func(obj): print obj.show() s1_obj = S1() Func(s1_obj) s2_obj = S2() Func(s2_obj)
class Animal: def __init__(self, name): # Constructor of the class self.name = name def talk(self): # Abstract method, defined by convention only raise NotImplementedError("Subclass must implement abstract method") class Cat(Animal): def talk(self): return 'Meow!' class Dog(Animal): def talk(self): return 'Woof! Woof!' animals = [Cat('Missy'), Dog('Lassie')] for animal in animals: print animal.name + ': ' + animal.talk()
類的方法 |
類的成員能夠分爲三大類:字段、方法和屬性。
注:全部成員中,只有普通字段的內容保存對象中,即:根據此類建立了多少對象,在內存中就有多少個普通字段。而其餘的成員,則都是保存在類中,即:不管對象的多少,在內存中只建立一份。
1、字段
字段包括:普通字段和靜態字段,他們在定義和使用中有所區別,而最本質的區別是內存中保存的位置不一樣,
class Foo: # 靜態字段 country = "China" def __init__(self, name): # 普通字段 self.name = name # 直接訪問靜態字段 Foo.country # 直接訪問普通字段 obj = Foo("山西")
由上述代碼能夠看出【普通字段須要經過對象來訪問】【靜態字段經過類訪問】,在使用上能夠看出普通字段和靜態字段的歸屬是不一樣的。
應用場景: 經過類建立對象時,若是每一個對象都具備相同的字段,那麼就使用靜態字段
方法包括:普通方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不一樣。
class Foo: #靜態方法 @staticmethod def xo(arg1, arg2): #無默認參數,可不傳參數,可傳任意參數 print("xo") #類方法 @classmethod def xxoo(cls): #定義類方法,至少有一個cls參數 print(cls) #普通方法,類中 def show(self): #定義普通方法,至少有一個self參數 print("show") # 調用靜態方法 Foo.xo(1,2) # 調用類方法 Foo.xxoo() # 調用普通方法 obj = Foo: obj.show()
相同點:對於全部的方法而言,均屬於類(非對象)中,因此,在內存中也只保存一份。
不一樣點:方法調用者不一樣、調用方法時自動傳入的參數不一樣。
屬性的基本使用
由屬性的定義和調用要注意一下幾點:
注意:屬性存在乎義是:訪問屬性時能夠製造出和訪問字段徹底相同的假象
屬性由方法變種而來,若是Python中沒有屬性,方法徹底能夠代替其功能。
class Foo: def __init__(self, name): self.name = name # 屬性,將方法僞形成一種字段 @property def end(self): return self.name # 修改end值 @end.setter def end(self, new_name): self.name = new_name obj = Foo("nick") # 調用屬性,不須要加括號 result2 = obj.end print(result2) # 調用修改end.setter屬性(自動將jenny傳入當參數new_name) obj.end = "jenny" result3 = obj.end print(result3)
屬性的兩種定義方式
屬性的定義有兩種方式:
裝飾器方式:在類的普通方法上應用@property裝飾器
咱們知道Python中的類有經典類和新式類,新式類的屬性比經典類的屬性豐富。( 若是類繼object,那麼該類是新式類 ) # ############### 定義 ############### class Goods: @property def price(self): return "nick" # ############### 調用 ############### obj = Goods() result = obj.price # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值 新式類,具備三種@property裝飾器 # ############### 定義 ############### class Goods(object): @property def price(self): print '@property' @price.setter def price(self, value): print '@price.setter' @price.deleter def price(self): print '@price.deleter' # ############### 調用 ############### obj = Goods() obj.price # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值 obj.price = 123 # 自動執行 @price.setter 修飾的 price 方法,並將 123 賦值給方法的參數 del obj.price # 自動執行 @price.deleter 修飾的 price 方法 注:經典類中的屬性只有一種訪問方式,其對應被 @property 修飾的方法 因爲新式類中具備三種訪問方式,咱們能夠根據他們幾個屬性的訪問特色,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除 class Goods(object): def __init__(self): # 原價 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 實際價格 = 原價 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deltter def price(self, value): del self.original_price obj = Goods() obj.price # 獲取商品價格 obj.price = 200 # 修改商品原價 del obj.price # 刪除商品原價 |
靜態字段方式,建立值爲property對象的靜態字段
因此,定義屬性共有兩種方式,分別是【裝飾器】和【靜態字段】,而【裝飾器】方式針對經典類和新式類又有所不一樣。
當使用靜態字段的方式建立屬性時,經典類和新式類無區別 class Foo: def get_bar(self): return 'nick' BAR = property(get_bar) obj = Foo() reuslt = obj.BAR # 自動調用get_bar方法,並獲取方法的返回值 print reuslt property的構造方法中有個四個參數
class Foo: def get_bar(self): return 'nick' # *必須兩個參數 def set_bar(self, value): return 'set value' + value def del_bar(self): return 'nick' BAR = property(get_bar, set_bar, del_bar, 'description...') obj = Foo() obj.BAR # 自動調用第一個參數中定義的方法:get_bar obj.BAR = "jenny" # 自動調用第二個參數中定義的方法:set_bar方法,並將「jenny」看成參數傳入 del Foo.BAR # 自動調用第三個參數中定義的方法:del_bar方法 obj.BAR.__doc__ # 自動獲取第四個參數中設置的值:description... 因爲靜態字段方式建立屬性具備三種訪問方式,咱們能夠根據他們幾個屬性的訪問特色,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除 class Goods(object): def __init__(self): # 原價 self.original_price = 100 # 折扣 self.discount = 0.8 def get_price(self): # 實際價格 = 原價 * 折扣 new_price = self.original_price * self.discount return new_price def set_price(self, value): self.original_price = value def del_price(self, value): del self.original_price PRICE = property(get_price, set_price, del_price, '價格屬性描述...') obj = Goods() obj.PRICE # 獲取商品價格 obj.PRICE = 200 # 修改商品原價 del obj.PRICE # 刪除商品原價 |
類成員的修飾符 |
每個類的成員都有兩種形式:
私有成員和公有成員的定義不一樣:私有成員命名時,前兩個字符是下劃線。(特殊成員除外,例如:__init__、__call__、__dict__等)
class Foo: xo = "xo" #公有字段 __ox = "ox" #私有字段 def __init__(self): self.name = "nick" #公有字段 self.__name2 = "nick" #私有字段
私有成員和公有成員的訪問限制不一樣:
靜態字段
class C: name = "公有靜態字段" def func(self): print C.name class D(C): def show(self): print C.name C.name # 類訪問 obj = C() obj.func() # 類內部能夠訪問 obj_son = D() obj_son.show() # 派生類中能夠訪問
class C: __name = "公有靜態字段" def func(self): print C.__name class D(C): def show(self): print C.__name C.__name # 類訪問 ==> 錯誤 obj = C() obj.func() # 類內部能夠訪問 ==> 正確 obj_son = D() obj_son.show() # 派生類中能夠訪問 ==> 錯誤
普通字段
class C: def __init__(self): self.foo = "公有字段" def func(self): print self.foo # 類內部訪問 class D(C): def show(self): print self.foo # 派生類中訪問 obj = C() obj.foo # 經過對象訪問 obj.func() # 類內部訪問 obj_son = D(); obj_son.show() # 派生類中訪問
class C: def __init__(self): self.__foo = "私有字段" def func(self): print self.foo # 類內部訪問 class D(C): def show(self): print self.foo # 派生類中訪問 obj = C() obj.__foo # 經過對象訪問 ==> 錯誤 obj.func() # 類內部訪問 ==> 正確 obj_son = D(); obj_son.show() # 派生類中訪問 ==> 錯誤
方法、屬性的訪問於上述方式類似,即:私有成員只能在類內部使用
ps:若是想要強制訪問私有字段,能夠經過 【對象._類名__私有字段明 】訪問(如:obj._C__foo),不建議強制訪問私有成員。
類的特殊成員 |
成員名前若是有兩個下劃線,則表示該成員是私有成員,私有成員只能由類內部調用。
表示類的描述信息
class Foo: """ 描述類信息 """ def func(self): pass print Foo.__doc__ #輸出:類的描述信息
__module__ 表示當前操做的對象在那個模塊
__class__ 表示當前操做的對象的類是什麼
#!/usr/bin/env python # -*- coding:utf-8 -*- class C: def __init__(self): self.name = 'nick'
from lib.aa import C obj = C() print obj.__module__ # 輸出 lib.aa,即:輸出模塊 print obj.__class__ # 輸出 lib.aa.C,即:輸出類
構造方法,經過類建立對象時,自動觸發執行。
class Foo: def __init__(self, name): self.name = name self.age = 18 obj = Foo('nick') # 自動執行類中的 __init__ 方法
析構方法,當對象在內存中被釋放時,自動觸發執行。
注:此方法通常無須定義,由於Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,由於此工做都是交給Python解釋器來執行,因此,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。
class Foo: def __del__(self): pass
對象後面加括號,觸發執行。
注:構造方法的執行是由建立對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()
# __call__ class Foo: def __init__(self): print("This is init") def __call__(self, *args, **kwargs): print("This is call") return "CC" obj = Foo() # 執行 __init__ obj() # 執行 __call__ result = Foo()() # 執行 __call__ print(result)
類或對象中的全部成員
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__ # 輸出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None} obj1 = Province('shangxi',10000) print obj1.__dict__ # 獲取 對象obj1 的成員 # 輸出:{'count': 10000, 'name': 'shangxi'} obj2 = Province('shangdong', 3888) print obj2.__dict__ # 獲取 對象obj1 的成員 # 輸出:{'count': 3888, 'name': 'shangdong'}
若是一個類中定義了__str__方法,那麼在打印對象時,默認輸出該方法的返回值。
class Foo: def __str__(self): return 'nick' obj = Foo() print obj # 輸出:nick
用於索引操做,如字典。以上分別表示獲取、設置、刪除數據
class Foo: def __getitem__(self, item): print(item) def __setitem__(self, key, value): print(key, value) def __delitem__(self, key): print(key) obj = Foo() obj["nick"] # 自動觸發執行 __getitem__ obj["nick"] = "jenny" # 自動觸發執行 __setitem__ del obj["nick"] # 自動觸發執行 __delitem__
該三個方法用於分片操做,如:列表
class Foo(object): def __getslice__(self, i, j): print '__getslice__',i,j def __setslice__(self, i, j, sequence): print '__setslice__',i,j def __delslice__(self, i, j): print '__delslice__',i,j obj = Foo() obj[-1:1] # 自動觸發執行 __getslice__ obj[0:1] = [11,22,33,44] # 自動觸發執行 __setslice__ del obj[0:2] # 自動觸發執行 __delslice__
用於迭代器,之因此列表、字典、元組能夠進行for循環,是由於類型內部定義了 __iter__
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): 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
#!/usr/bin/env python # -*- coding:utf-8 -*- obj = iter([11,22,33,44]) while True: val = obj.next() print val
在解析父類的__init__時,定義解析順序的是子類的__mro__屬性,內容爲一個存儲要解析類順序的元組。
class A(object): def __init__(self): print ' -> Enter A' print ' <- Leave A' class B(A): def __init(self): print ' -> Enter B' # A.__init__(self) super(B, self).__init__() print ' <- Leave B' class C(A): def __init__(self): print " -> Enter C" # A.__init__(self) super(C, self).__init__() print " <- Leave C" class D(B, C): def __init__(self): print " -> Enter D" # B.__init__(self) # C.__init__(self) super(D, self).__init__() print " <- Leave D" if __name__ == "__main__": d = D() print "MRO:", [x.__name__ for x in D.__mro__] print type(D.__mro__) 執行以上代碼,獲得的輸出爲: -> Enter D -> Enter C -> Enter A <- Leave A <- Leave C <- Leave D MRO: ['D', 'B', 'C', 'A', 'object'] <type 'tuple'>
__slot__定義類中能夠被外界訪問的屬性。
當父類中定義了__slot__時,不能向父類中添加屬性。若是子類中沒有定義__slot__,則子類不受父類__slot__定義的限制。
若是父類與子類中都定義了__slot__,則郵箱的結果爲父類與子類__slot__的合集。
閱讀如下代碼:
class Foo(object): def __init__(self): pass obj = Foo() # obj是經過Foo類實例化的對象
上述代碼中,obj 是經過 Foo 類實例化的對象,其實,不只 obj 是一個對象,Foo類自己也是一個對象,由於在Python中一切事物都是對象。
若是按照一切事物都是對象的理論:obj對象是經過執行Foo類的構造方法建立,那麼Foo類對象應該也是經過執行某個類的 構造方法 建立。
print type(obj) # 輸出:<class '__main__.Foo'> 表示,obj 對象由Foo類建立 print type(Foo) # 輸出:<type 'type'> 表示,Foo類對象由 type 類建立
因此,obj對象是Foo類的一個實例,Foo類對象是 type 類的一個實例,即:Foo類對象 是經過type類的構造方法建立。
那麼,建立類就能夠有兩種方式:
1> 普通方式
class Foo(object): def func(self): print 'hello word'
2> 特殊方式(type類的構造函數)
def func(self): print 'hello word' Foo = type('Foo',(object,), {'func': func}) #type第一個參數:類名 #type第二個參數:當前類的基類 #type第三個參數:類的成員
==》 類 是由 type 類實例化產生
那麼問題來了,類默認是由 type 類實例化產生,type類中如何實現的建立類?類又是如何建立對象?
答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化建立,因此,咱們能夠爲 __metaclass__ 設置一個type類的派生類,從而查看 類 建立的過程。
class MyType(type): def __init__(self, what, bases=None, dict=None): super(MyType, self).__init__(what, bases, dict) def __call__(self, *args, **kwargs): obj = self.__new__(self, *args, **kwargs) self.__init__(obj) class Foo(object): __metaclass__ = MyType def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs) # 第一階段:解釋器從上到下執行代碼建立Foo類 # 第二階段:經過Foo類建立obj對象 obj = Foo()
isinstance(obj, cls) & issubclass(sub, super) |
isinstance(obj, cls)
檢查是否obj是不是類 cls 的對象
class Foo(object): pass obj = Foo() isinstance(obj, Foo)
issubclass(sub, super)
檢查sub類是不是 super 類的派生類
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)
異常處理 |
一、異常簡介
在編程過程當中爲了增長友好性,在程序出現bug時通常不會將錯誤信息顯示給用戶,而是現實一個提示的頁面,通俗來講就是不讓用戶看見大黃頁!!!
try: pass except Exception,ex: pass
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
異常類只能用來處理指定的異常狀況,若是非指定異常則沒法處理。
# 未捕獲到異常,程序直接報錯 s1 = 'hello' try: int(s1) except IndexError as e: print e except (KeyError, ValueError) as e: print e # 萬能異常 except Exception,e: print e
try: # 主代碼塊 pass except KeyError,e: # 異常時,執行該塊 pass else: # 主代碼塊成功執行完,執行該塊 pass finally: # 不管異常與否,最終執行該塊 pass
try: raise Exception('錯誤了。。。') except Exception,e: print e
class NickException(Exception): def __init__(self, msg): self.message = msg def __str__(self): return self.message try: raise NickException('個人異常') except NickException,e: print e
# assert 條件 # 條件成立則pass,條件不成立則報錯 assert 1 == 1 assert 1 == 2
反射 |
python中的反射功能是由如下四個內置函數提供:hasattr、getattr、setattr、delattr,改四個函數分別用於對對象內部執行:檢查是否含有某成員、獲取成員、設置成員、刪除成員。
# commons.py 文件 name = "nick" def f1(): return "This is f1." def f2(): return "This is f2." def nb(): return "This is niubily." # index.py 文件 import commons #根據字符串的形式去某個模塊中尋找東西 target_func = getattr(commons,"f1") # 找函數 result = target_func() print(result) target_func = getattr(commons,"name") # 找全局變量 print(target_func) target_func = getattr(commons,"age",None) # 找不到返回None print(target_func) #根據字符串的形式去某個模塊中判斷東西是否存在 tarhas_func = hasattr(commons,"f5") # 找函數 print("before:",tarhas_func) # tarhas_func = hasattr(commons,"name") # 找全局變量 # print(tarhas_func) #根據字符串的形式去某個模塊中設置東西 setattr(commons,"f5","lambda x: return \"This is new func.\"") # 設置一個函數 setattr(commons,"age",18) # 設置全局變量 tarhas_func = hasattr(commons,"f5") # 檢查函數是否存在 print("after:",tarhas_func) #根據字符串的形式去某個模塊中刪除東西 delattr(commons,"f5") # 刪除一個函數 tarhas_func = hasattr(commons,"f5") # 檢查函數是否存在 print("end:",tarhas_func)
# 經過字符串的形式,導入模塊。起個別名 ccas。 comm = input("Please:") ccas = __import__(comm) ccas.f1() # 須要作拼接導入時後加 fromlist=True(不然只導入lib) ccas = __import__("lib."+comm, fromlist=True)
##### 路由系統 ##### # 輸入 模塊名/函數名 (例如:commons/nb) url = input("Please input you want url:") target_module, target_func = url.split("/") #m = __import__("lib."+target_module,fromlist=True) m = __import__(target_module) if hasattr(m,target_func): target_func = getattr(m,target_func) result = target_func() print(result) else: print("Sorry,it's 404 not found.")
單例模式 |
單例模式存在的目的是保證當前內存中僅存在單個實例,避免內存浪費!!!
(程序若是併發量大的話,內存裏就會存在很是多功能上如出一轍的對象。存在這些對象確定會消耗內存,對於這些功能相同的對象能夠在內存中僅建立一個,須要時都去調用)
# 單例模式 class Foo: __n = None def __init__(self): self.name = "nick" self.age = 18 self.job = "pythoner" @staticmethod def dl(): if Foo.__n: return Foo.__n else: Foo.__n = Foo() return Foo.__n # 建立對象時不能再直接使用:obj = Foo(),而應該調用特殊的方法:obj = Foo.dl() 。 f1 = Foo.dl() print(f1) f2 =Foo.dl() print(f2) f3 =Foo.dl() print(f3) # 運行結果 <__main__.Foo object at 0x0000000001142390> <__main__.Foo object at 0x0000000001142390> <__main__.Foo object at 0x0000000001142390>
裝飾器方式單例模式
# 裝飾器方式單例模式 def singleton(argv): dic = {} def s(*args, **kwargs): if argv not in dic: dic[argv] = argv(*args, **kwargs) return dic[argv] else: return dic[argv] return s # 類上加單例裝飾器 @singleton class Foo: pass @singleton class Foo2: pass