面向對象2

面向對象(進階)

1,針對上一節做業須要補充的幾點知識html


├── daytest
│   ├── test.py
│   └── test.txt
└── test
└── t1.py

目錄結果如上,在test.py中有一個類C1,根據類建立一個對象obj,而後把對象pickle到
test.txt中,在另外的一個目錄下,如何把obj反序列化回來?思路要想反序列化回來必須導入類。

解答:
若是,test.py和t1.py在同一級目錄下,直接導入類便可---> from test import C1。
如上這種狀況,該怎麼辦,

sys.path.append(os.path.dirname(os.path.dirname(__file__))) # 先把父目錄添加到環境變量中
from daytest.test import C1 #
r = os.path.join(os.path.dirname(os.path.dirname(__file__)), "daytest", "test.txt")
r = pickle.load(open(r, "rb"))
print(r.name, r.age)java

 

一,多態(多種形態,或 多種類型)

python默認自己支持多態,java、C#默認是不支持多態的。

例如:

# JAVA或者C#中,在傳參數的時候必須指定參數的類型,int,float等,
#而python自己,默承認以傳多種類型。python

 1 def func(int, args)  
 2     print(args)
 3 
 4 func(12)         #正確
 5 func("alex")    #報錯
 6 
 7 
 8 可是若是:C#和JAVA也要支持多態,則必須藉助繼承來實現,以下:
 9 class A:
10     def __init__(self):
11         pass
12 
13 class B(A):
14 
15     def __init__(self):
16         pass
17 
18 class C(A):
19     def __init__(self):
20         pass
21 
22 # args參數,必須是A類型,或者A的子類類型
23 def func(A, args):  
24         print(args)
25         
26 # obj = B()
27 # obj = C()
28 obj = A()
29 func(obj)
30 # 此時的func函數就能夠支持多種類型
View Code

python的多態,也增長了看源碼的難度,由於當源碼中有函數時,你並不知道它是什麼類型!程序員

 

 

二,類成員之字段和方法

  

a, 普通字段和靜態字段

 1 class Foo:
 2     CC = "中國"  # 靜態字段,保存在類中,能夠用類或者對象訪問,在代碼加載時已經建立
 3                  # 強烈建議靜態字段要用類進行訪問,由於在java和c中都是用類訪問。
 4 
 5     def __init__(self, name):
 6         self.name = name  # 普通字段(也有人稱爲動態字段),保存在對象中
 7                           #  只能使用對象訪問
 8 
 9     def show(self):
10         pass
11 
12 obj = Foo("河南")
13 print(obj.name)
14 
15 r = Foo.CC    # 用類訪問
16 r1 = obj.CC      # 用對象訪問   
17 print(r)
18 print(r1)
19 
20 # 注意靜態字段能夠用del Foo.CC去刪除
21 
22 結果:
23 
24 河南
25 中國
26 中國
View Code

 

總結:
靜態字段,保存在類中,能夠用類或者對象訪問,在代碼加載時已經建立。強烈建議用類訪問。
普通字段,保存在對象中,只能使用對象訪問,在代碼加載時沒有建立,由於代碼加載時並無建立類。web

 

b, 靜態方法和普通方法

 

 1 class Foo:
 2     CC = "中國"
 3 
 4     def __init__(self, name):
 5         self.name = name
 6 
 7     def show(self):  # 普通方法,方法屬於類,由對象調用並執行
 8         print(self.name)
 9 
10     @staticmethod
11     def f1(args1, args2):  # 靜態方法, 也屬於類,由類來調用並執行
12         print(args1, args2)
13 
14     def f2(self):
15         print("hello")
16 
17 obj = Foo("河南")
18 print(obj.name)
19 obj.f1("hello", "world")   # 由對象調用, 浪費內存。
20 
21 Foo.f1("hello", "world") # 由類去調用,因此靜態方法要用類去調用!
22 
23 結果:
24 
25 河南
26 hello world
27 hello world
View Code

 

總結:
# 對於不使用對象的方法(如f2方法)均可以改成,靜態方法,這樣就能夠更加節省內存。
# 靜態方法其實本質上就是函數,若是該函數跟Foo這個類沒有任何的聯繫,徹底能夠寫到類外面。數據庫

 

c, 類方法,本質也是一種特殊的靜態方法

 1 class Foo:
 2     CC = "中國"
 3 
 4     def __init__(self, name):
 5         self.name = name
 6 
 7     def show(self):  # 普通方法,方法屬於類,由對象調用並執行
 8         print(self.name)
 9 
10     @staticmethod
11     def f1(a, b):  # 靜態方法, 也屬於類,由類來調用並執行
12         print(a, b)
13 
14     @classmethod  # 類方法,本質也是一種靜態方法,必須會有一個參數cls,在調用時不用傳入參數,
15     def f2(cls):  # 由Python自動傳遞
16         print(cls) # ----> 輸出爲:類名 <class '__main__.Foo'>
17 
18 Foo.f2()
19 
20 結果:
21 
22 <class '__main__.Foo'>   # 這個__main__,很好理解!
View Code

總結:
全部的方法都屬於類:
1, 普通方法:至少有一個self, 由對象執行
2, 靜態方法:任意參數, 由類執行(對象執行)
3, 類方法: 至少有一個cls, 由類執行(對象執行)
切記:不到萬不得已,靜態方法和類方法不能用對象執行。設計模式

 

 

三, 類成員之屬性(不三不四的東西,具備方法的定義形式,具備字段的訪問形式)

1,類實現的簡單的分頁功能

 1 class Paper:
 2 
 3     def __init__(self, all_count):
 4         self.all_count = all_count
 5 
 6     @property
 7     def all_paper(self):
 8         a1, a2 = divmod(self.all_count, 10)
 9         if a2 == 0:
10             return a1
11         else:
12             return a1 + 1
13 p = Paper(101)
14 # p.all_count    字段
15 # p.all_paper()  方法
16 ret = p.all_paper   # 在沒有@property以前,ret = p.all_paper(),便可得到結果
17 print(ret)            #  加上@property以後,不加()就能夠調用。
View Code

 

2, 屬性的表達形式之一

 1 class Paper:
 2 
 3     def __init__(self, all_count):
 4         self.all_count = all_count
 5 
 6     @property
 7     def all_paper(self):
 8         a1, a2 = divmod(self.all_count, 10)
 9         if a2 == 0:
10             return a1
11         else:
12             return a1 + 1
13 
14     @all_paper.setter            # -----------> 注意這裏的裝飾器的名字必須是上面的函數名
15     def all_paper(self, value):     # -----------> 一樣,注意理解,下面相似
16         print(value)
17 
18     @all_paper.deleter
19     def all_paper(self):
20         print("all_paper")
21 
22 p = Paper(101)
23 
24 ret = p.all_paper    # ---------> 執行對應的@property下面的方法
25 print(ret)
26 p.all_paper = 888     # ---------> 執行對應的@all_paper.setter下面的方法,並把888賦值給方法中的value
27 del p.all_paper         # ---------> 執行對應的@all_paper.deleter下面的方法
28 
29 
30 結果:
31 11
32 888
33 all_paper
View Code

注意:這裏的獲取、修改、刪除,只是執行了對應的方法,方法裏面具體執行什麼能夠本身去定義。
而不是真正的刪除,獲取,修改。session

 

3,屬性的另一種表達方式(比較常見,特別是在源碼中特別常見!)

 

 1 class Pager:
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def f1(self):
 6         return "hello world"
 7 
 8     def f2(self, value):
 9         print(value)
10 
11     def f3(self):
12         print("del")
13 
14     foo = property(fget=f1, fset=f2, fdel=f3) # fget,fset, fdel都是python定義好的,當函數名看成參數傳遞
15 
16 p = Pager("tom")
17 result = p.foo   # -------->只要是這樣的書寫格式就去執行f1方法
18 print(result)
19 
20 p.foo = "LinTao" #--------->只要是這樣的書寫格式就去執行f2方法,而且把等號後面的值傳遞給f2的中的參數value
21 
22 del p.foo         #--------->只要是這樣的書寫格式就去執行f3方法
23 
24 
25 結果以下:
26 hello world
27 LinTao
28 del
View Code

 

 

 

四, 類成員之成員修飾符(顧名思義就是修飾成員的:字段,方法,屬性)

在python中相對比較簡單,而在java和C#裏面有四種:公有的,私有的,一個程序集裏面可用的,一個是受保護的,
在python中就有兩個:
1, 公有(在內部,外部都能訪問獲得)
2, 私有(只能類自己成員內部能夠訪問)app

 

字段

1,私有普通字段框架

 1 class Foo:
 2     def __init__(self, name):
 3         self.__name = name    # ------> 私有, 當在字段前面加兩個下劃線,字段就變成私有的字段,只能內部訪問
 4 
 5     def f1(self):
 6         print(self.__name)  # ------> 內部調用
 7 
 8 
 9 class Bar(Foo):
10     def f2(self):
11         print(self.__name)
12 
13 obj = Foo("tom")
14 obj.f1()        #--------->在內部訪問,能訪問獲得    
15 print(obj.name)  # --------> 在外部調用,會報錯!!! 
16 obj1 = Bar("lily") # -------> 經過外部訪問, 不能訪問,會報錯!!!
17 obj1.f2()
View Code

 

2,私有靜態字段

 1 class Foo:
 2     __CC = "hello world"
 3 
 4     def __init__(self, name):
 5         self.__name = name
 6 
 7     @staticmethod
 8     def f1():
 9         print(Foo.__CC)
10 
11 # print(Foo.CC)   # ------->在外部不能訪問,會報錯!
12 Foo.f1()          # ------->在內部能夠訪問到
View Code

 

總結:方法和屬性,同字段同樣,私有的只能在內部訪問。可是有一種特殊狀況,以下:

 

 1 class Foo:
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def __f1(self, name, age):
 6         self.name = name
 7         print(name, age)
 8 
 9     def f2(self):
10         Foo("tom").__f1("tom", 22)
11 
12 
13 obj = Foo("tom")
14 obj.f2()                 # ---------> 私有的方法f1,只能在內部進行訪問。
15 # obj.Foo__f1("lily", 23)# ---------> 私有的方法f1,在外部訪問會報錯!!!
16 obj._Foo__f1("lily", 23) #----------> 若是強制想在外部訪問,必須在類名的前面加一個下劃線。
View Code

 

強烈建議:不到萬不得已,不能這麼去用!!!!!

 

 

 五, 特殊成員

# __doc__ 註釋用
# __module__ 表示當前操做的對象在哪一個模塊, 輸出模塊的位置

# __class__ 表示當前操做的對象的類是什麼

舉例:test.py 以下:

 1 class C1:
 2 def __init__(self):
 3     pass
 4 
 5 def f1(self):
 6     pass
 7     
 8     
 9     
10 from dtest.test import C1
11 obj1 = C1()
12 print(obj1.__class__)
13 print(obj1.__module__)
14 
15 結果以下:
16 
17 <class 'dtest.test.C1'>
18 dtest.test
View Code

 

# __init__ 構造方法,建立對象的時候將會自動觸發該方法。
# __del__ 析構方法,當對象的內存被釋放時,自動觸發執行。
# 注意:此方法無需定義,由於python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,
# 由於此工做都是交給python解釋器來執行,因此,析構函數的調用是由解釋器在進行垃圾回收時自動
# 觸發執行的。


# __call__ 對象後面加括號,觸發執行
# 注意:構造方法的執行是由建立對象觸發的,即對象 = 類名();而對於__call__方法的執行是由對象
# 後加括號觸發的,即:對象() 或者 類()()

 1 class Foo:
 2         def __init__(self):
 3             pass
 4 
 5         def __call__(self, *args, **kwargs):
 6             print("執行call方法!")
 7 
 8     obj = Foo()
 9     obj()
10 
11     結果以下:
12     執行call方法!
View Code

 

# __str__ 若是定義了該方法,那麼在打印 對象 時,默認輸出該對象的返回值!

 1 class Foo:
 2 def __init__(self, name, age):
 3     self.name = name
 4     self.age = age
 5 
 6 def __str__(self):
 7     return "{} {}".format(self.name, self.age)
 8 
 9 obj = Foo("tom", "21")
10 print(obj)
11 
12 結果以下:
13 tom 21
View Code

 

# __add__ 當兩個對象相加時,會自動調用__add__,裏面的方法,獲取返回結果!

 1 class Foo:
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5 
 6     def __add__(self, other):
 7         return self.name, other.age  # 咱們去obj中的name和obj1中的age
 8 
 9 obj = Foo("tom", "21")
10 obj1 = Foo("lily", "72")
11 ret = obj + obj1
12 print(ret)
13 
14 結果以下:
15 
16 ('tom', '72')
View Code

 

# __dict__ 獲取對象中封裝的全部的數據並放入字典中。很是重要!!!
# 固然,該方法也能夠獲取類中封裝的數據,並放入字典。這個用的少一些

class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def f1(self):
        pass

    def f2(self):
        pass

obj = Foo("tom", "21")
print(obj.__dict__)

print(Foo.__dict__)


結果以下:
{'age': '21', 'name': 'tom'}  # 獲取對象obj中封裝的數據

{'__doc__': None, '__init__': <function Foo.__init__ at 0x000000000091AEA0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, 'f1': <function Foo.f1 at 0x000000000091AF28>, '__module__': '__main__', 'f2': <function Foo.f2 at 0x0000000000926048>}

 

下面三種重要的方法很是重要,在web框架中自定義session框架會用到這個!!!
# __setitem__
# __getitem__
# __delitem__

 1 class Foo:
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5 
 6     def __getitem__(self, item):
 7         return 123, item
 8 
 9     def __setitem__(self, key, value):
10         print(key, value)
11 
12     def __delitem__(self, key):
13         print(key)
14 
15 obj = Foo("tom", "21")
16 # 語法對應關係
17 ret = obj["hello"]  # 只要是:對象["xxx"],這種格式,就會執行__getitem__方法,並把"xxx"傳遞給item
18 print(ret)
19 
20 obj["k1"] = 88  # 只要是:對象["xx"] = xxx,這種格式,就會執行__setitem__方法,並把"xx"傳遞給key,"xxx"傳遞給value
21 
22 del obj["ok"]  #只要是:del 對象["xxx"],這種格式,就會執行__delitem__方法,並把"xxx"傳遞給
View Code

 

還有一種特殊的切片的方式的應用,和上面相似

 1 class Foo:
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5 
 6     def __getitem__(self, item):
 7         print(item, type(item))                    # 類型是切片
 8         print(item.start, item.stop, item.step) # 包括起始,步長
 9 
10     def __setitem__(self, key, value):
11         print(key, value)
12 
13     def __delitem__(self, key):
14         print(key)
15 
16 obj = Foo("tom", "21")
17 
18 obj[1:5:2]
19 obj[1:5:2] = 888
20 del obj[1:5:2]
21 
22 
23 結果以下:
24 
25 slice(1, 5, 2) <class 'slice'>
26 1 5 2
27 slice(1, 5, 2) 888
28 slice(1, 5, 2)
View Code

 

# __iter__ 當用for循環一個對象的時候,會去執行__iter__方法,而後拿到返回值,再進行迭代。list,字典,等之因此
能進行迭代就是由於內部使用了__iter__方法

 1 class C1:
 2     def __init__(self):
 3         pass
 4 
 5     def __iter__(self):
 6         yield 1
 7         yield 2
 8 
 9 obj = C1()
10 for i in obj:
11     print(i)
12     
13     
14 結果以下:
15 
16 1
17 2
View Code

 

# __new__ 和 __metaclass__ 能夠解釋,是由誰建立類的

 

1,當你使用class關鍵字時,python解釋器自動建立了這個對象。
2,可是就和大多數事情同樣,python仍然提供給你了手動處理的方法,那就是內置函數type。
type是python中一般的元類。元類就是在python背後建立全部類的元類,建立類的類。


語法格式以下:
type(類名, 父類的元組(針對繼承的狀況,能夠爲空),包含屬性的字典(名稱和值))

 

第一種方式:(常見)

class Foo(object):
	def __init__(self, name):
		self.name = name

	def f1(self):
		print("hello world")

f = Foo("tom")
f.f1()
print(type(Foo))   # <class 'type'> Foo來自type,說明類是由type建立的

  

  第二種方式:(特殊)

  例1.

  

def func(self):
	print("hello world")

Foo = type('Foo', (), {'f1': func})
#type第一個參數:類名
#type第二個參數:當前類的基類
#type第三個參數:類的成員

obj = Foo()
obj.f1()
print(type(Foo))   # <class 'type'> Foo來自type,說明類是由type建立的

  

  例2.

  

def func(self):
print(self.name)


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

Foo = type('Foo', (object, ), {'f1': func, '__init__': __init__})
obj = Foo("tom", 21)
obj.f1()
print(type(obj))
print(type(Foo))
 
執行結果:
tom
<class 'type'>
<class '__main__.Foo'>


在python中:一切皆對象!類一樣也是對象!
經過以上:咱們能夠看出obj對象是由類Foo實例化過來的,Foo類是經過type類產生的,
到底type是如何建立類的,類又是如何產生對象的呢?
1,建立類是經過元類type來實現, 其中類中有一個___metaclass___屬性(表示該類是由誰實例化建立的)
2,類實例化產生對象,則和__new__方法關係密切!

 

__metaclass__是什麼?

建立類的過程:
1, 好比當你寫上class Foo(object)時,類對象Foo並無在內存中建立Foo,python會在類的定義中找到__metaclass__屬性。
若是找到了,python就會用它來建立類對象,若是沒有找到,就會去父類中尋找__metaclass__屬性,若是都找不到就會在模塊
層次去尋找__metaclass__,並嘗試一樣的操做。若是仍是找不到__metaclass__,python就會用內置的type來建立這個類對象。

到底__metaclass中放置什麼代碼呢?答案是能夠建立一個類的代碼,什麼又能夠建立一個類呢?!type或者子類化type的東西。
type建立類的表達式如上。

元類type的用途有那些呢?
元類的主要用途是建立API。一個典型的例子是Django ORM。元類的主要目的就是爲了當建立類時可以自動地改變類。一般,你會爲API
作這樣的事情,你但願能夠建立符合當前上下文的類。還能夠輕易的作到 1) 攔截類的建立 2) 修改類 3) 返回修改以後的類

 

__new__是什麼?

在 Python 中存在於類裏面的構造方法 __init__() 負責將類的實例化,而在 __init__() 啓動以前,__new__() 決定是否要使用該
__init__() 方法,由於__new__() 能夠調用其餘類的構造方法或者直接返回別的對象來做爲本類的實例。

一般來講,新式類開始實例化時,__new__()方法會返回cls(cls指代當前類)的實例,而後該類的__init__()方法做爲構造方法會接收
這個實例(即self)做爲本身的第一個參數,而後依次傳入__new__()方法中接收的位置參數和命名參數。

事實上若是(新式)類中沒有重寫__new__()方法,即在定義新式類時沒有從新定義__new__()時,Python默認是調用該類的直接父類的
__new__()方法來構造該類的實例,若是該類的父類也沒有重寫__new__(),那麼將一直按此規矩追溯至object的__new__()方法,由於
object是全部新式類的基類。

 

類的建立過程以及如何經過類來建立對象的class MyType(type):

class MyType(type)
     def __init__(self, what, bases=None, dict=None):
        # print("***MyType.__init__")
        super(MyType, self).__init__(what, bases, dict)
 
    def __call__(self, *args, **kwargs):
        # print("***MyType.__call__")
        obj = self.__new__(self, *args, **kwargs)
        self.__init__(obj)
 
 
class Foo(object, metaclass=MyType):
    # __metaclass__ = MyType
    def __init__(self):
        # print("***Foo.__init__")
        pass
 
    def __new__(cls, *args, **kwargs):
        # print("***Foo.__new__")
        return object.__new__(cls, *args, **kwargs)
# 第一階段:解釋器從上到下執行代碼建立Foo類
# 第二階段:經過Foo類建立obj對象
obj = Foo()

  

  首先會加載class MyType 和 Class Foo(記住此時並無建立Foo),加載完以後因爲發現了metaclass,則會直接執行MyType類中的__init__方法,此時就是在用元類type建立類Foo,此時super(MyType, self).__init__(what, bases, dict)中的self即爲Foo,此時就已經建立了Foo類

 

第二階段:經過Foo類建立obj對象

obj = Foo(),此時開始執行這一行代碼,Foo爲元類建立的類對象(),至關於類()(),因而就開始調用Mytype中__call__方法,__call__方法中才是建立類的開始。

obj = self.__new__(self, *args, **kwargs) 注意此時self爲Foo,因此開始調用了Foo類中的__new__方法,其實類的真正實例化是從這一步開始的。

self.__init__(obj) # 執行類的初始化,把self傳進去。



注意事項:以上是在python3環境下實現的,python2中寫法會有所區別,詳見博客 http://www.cnblogs.com/wupeiqi/p/4766801.html

 

 

六, 面向對象其餘知識點  

1,isinstance,查看對象是不是由某個類的實例

 1 class C1:
 2     pass
 3 
 4 obj = C1()
 5 
 6 r = isinstance(obj, C1)
 7 print(r)
 8 
 9 結果以下:
10 True
View Code

# 注意若是,C1繼承了C2,那麼r = isinstance(obj, C2)也一樣會返回True,不只是子類的實例
#也是父類的實例

 

2,issubclass,查看某個類是不是其餘類的子類

 1 class C1:
 2     pass
 3 
 4 
 5 class C2(C1):
 6     pass
 7 
 8 r = issubclass(C2, C1)
 9 print(r)
10 
11 結果以下:
12 True
View Code

 

3,執行父類的方法(這是修改源碼的一種很是重要的思路!!!!!!)

a, 執行父類的第一種方法

正常狀況下,Bat類在繼承Foo類之後,仍然會先執行本身的f1方法
可是加上super(Bat,self).f1()以後則會主動去執行Foo的f1方法。

 1 class Foo:
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def f1(self):
 6         print("Foo.f1")
 7 
 8 
 9 class Bat(Foo):
10     def f1(self):
11         # 主動執行父類的f1()方法
12         super(Bat, self).f1()
13         print("Bat.f1")
14 
15 obj = Bat("tom")
16 obj.f1()
View Code

 

b, 執行父類的第二種方法,可是python3.0之後不建議這麼去用

 

 1 class Foo:
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def f1(self):
 6         print("Foo.f1")
 7 
 8 
 9 class Bat(Foo):
10     def f1(self):
11         # 主動執行父類的f1()方法
12         Foo.f1(self)          # -----------> 注意:若是父類中有參數,還得辦法把參數傳進去
13         print("Bat.f1")
14 
15 obj = Bat("tom")
16 obj.f1()
View Code

 

4,實例之自定義有序字典

 1 class MyDict(dict):   # 建立自定義字典,繼承字典
 2     def __init__(self):
 3         self.li = []    # 建立了一個空列表
 4         super(MyDict, self).__init__()  # 不能改變原來的內容
 5 
 6     def __setitem__(self, key, value):
 7         self.li.append(key)  # 每增長一個值即把key添加到列表中
 8         super(MyDict, self).__setitem__(key, value)  # 不能改變原來的內容
 9 
10     def __str__(self):  # 打印對象執行此方法
11         temp_list = []
12         for key in self.li:
13             value = self.get(key)    # 執行父類的get方法,取出value的值
14             temp_list.append("'%s': %s" % (key, value,))
15         temp_str = "{" + ",".join(temp_list) + "}"
16         return temp_str
17 
18 
19 obj = MyDict()
20 obj["k1"] = 123
21 obj["k2"] = 456
22 print(obj)
23 
24 結果以下:
25 
26 {'k1': 123,'k2': 456}
View Code

 

 

七,面向對象之單例模式

# 設計模式(20多種設計模式)之單例模式:只有一個實例
# 設計模式是就爲了使代碼具備更好的擴展性
# 單例模式例如:數據庫鏈接池(即無論有多少人訪問,只有一個鏈接池,不可能存在大量的鏈接池。)

 1 class Foo:
 2     """
 3     構造單例模式
 4     """
 5     instance = None
 6 
 7     def __init__(self, name):
 8         self.name = name
 9 
10     @classmethod
11     def get_instance(cls):
12         if cls.instance:
13             return cls.instance
14         else:
15             obj = cls("alex")
16             cls.instance = obj
17             return obj
18 
19 obj1 = Foo.get_instance()
20 print(obj1)
21 obj2 = Foo.get_instance()
22 print(obj2)
23 
24 結果以下:內存地址是同樣的。
25 <__main__.Foo object at 0x0000000000922470>
26 <__main__.Foo object at 0x0000000000922470>
構造單例模式

 

 

八,異常處理

1,異常處理的種類(python中的異常種類很是多,每一個異常專門用於處理某一項異常!!!)

 

a, 常見的異常處理類型

AttributeError 試圖訪問一個對象沒有的樹形,好比foo.x,可是foo沒有屬性x
IOError 輸入/輸出異常;基本上是沒法打開文件
ImportError 沒法引入模塊或包;基本上是路徑問題或名稱錯誤
IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊
IndexError 下標索引超出序列邊界,好比當x只有三個元素,卻試圖訪問x[5]
KeyError 試圖訪問字典裏不存在的鍵
KeyboardInterrupt Ctrl+C被按下
NameError 使用一個還未被賦予對象的變量
SyntaxError Python代碼非法,代碼不能編譯(我的認爲這是語法錯誤,寫錯了)
TypeError 傳入對象類型與要求的不符合
UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是因爲另有一個同名的全局變量,
致使你覺得正在訪問它
ValueError 傳入一個調用者不指望的值,即便值的類型是正確的

 

b, 萬能的異常處理類型Exception

注意:對於特殊處理或提醒的異常須要先定義,最後定義Exception來確保程序正常運行

 1 s = input("age:")
 2 try:  # 正確則執行try塊裏面的內容
 3     int(s)
 4     print(s)
 5 except ValueError as ex:  # python會一級一級的向下檢查,只要符合條件就再也不向下執行   
 6     print(ex)
 7 except IndexError as ex:
 8     print(ex)
 9 except Exception, e:
10     print '錯誤'
View Code

 

2,異常的其餘結構(必定要注意執行的順序)

 1 try:
 2     # 主代碼塊
 3     pass
 4 except KeyError,e:
 5     # 異常時,執行該塊
 6     pass
 7 else:
 8     # 主代碼塊執行完,執行該塊
 9     pass
10 finally:
11     # 不管異常與否,最終執行該塊
12     pass
View Code

 

3,主動觸發異常

 1 s = input("age:")
 2 try:
 3     raise Exception("主動錯誤一下!")  # 建立一個Exception對象,此處也可改成ValueError,想拋什麼拋什麼
 4     int(s)
 5     print(s)
 6 except ValueError as ex:
 7     print(ex)
 8 except IndexError as ex:
 9     print(ex)
10 except Exception as tx:  # self.message = "主動錯誤一下!"
11     print(tx)     # __str__, return self.message
12 else:
13     pass
14 finally:
15     pass
View Code

 

4,自定義異常

 1 class MyException(Exception):
 2     def __init__(self, msg):
 3         self.message = msg
 4 
 5     def __str__(self):
 6         return self.message
 7 
 8 try:
 9     raise MyException("個人異常處理")
10 except MyException as e:
11     print(e)
12 
13 結果以下:
14 個人異常處理
View Code

 

5,斷言(相似於if...pass... + raise主動拋出異常),條件經過才能向下執行。

1 assert 1 == 1
2 print("ok")
View Code
相關文章
相關標籤/搜索