1. 程式人生 > >Python學習筆記之面對象與錯誤處理

Python學習筆記之面對象與錯誤處理

實現 單繼承 父類 成對 數據類型 itl 同時 屬性 子類

反射

__import__()函數用於加載類和函數

__import__(name[, globals[, locals[, fromlist[, level]]]])
    參數說明:
        name -- 模塊名

getattr() 函數用於返回一個對象屬性值。

getattr(object, name[, default])
    參數
        object -- 對象。
        name -- 字符串,對象屬性。
        default -- 默認返回值,如果不提供該參數,在沒有對應屬性時,將觸發 AttributeError。

執行 func()

data 
= input("請輸入地址:") array = data.split(/) userspace = __import__(backend+array[0]) model = getattr(userspance, array[0]) func = getattr(model, array[1]) func() # 應用於路由反射 # Django擴展 def activator(request, viewfile, view, action, arg): namespace = __import__(viewfile) module = getattr(namespace.Views, view) func
= func(module, arg) result = func(action, arg) return result

面對象

# 理解Python之self
    首先明確的是self只有在類的方法中才會有,獨立的函數或方法時不必帶有self的。
    self在定義類的方法時是必須有的,雖然在調用時不必傳入相應的參數。
    self名稱不是必須的,在Python中self不是關鍵詞,你可以定義成a或b或其他的名字都是可以的,
    但是和約定成俗,不要搞另類,大家會不明白的。


·self指的是類實例對象本身(註意:不是類本身)


# __init__() 實例化一個動作,初始化類的屬性
類實例創建之後調用,對當前對象的實例的一些初始化,沒有返回值 ·這個方法一般用於初始一個類 ·但是 當實例化一個類的時候,__init__並不是一個被調用的,第一個被調用的是__new__ # __str__() ·這是一個內置方法,只能返回字符串,並且只能有一個參數self # __new__() 靜態方法 ·創建類實例的方法,創建對象時調用,返回當前對象的一個實例 object將__new__()方法定義為靜態方法,並且至少需要傳遞一個參數cls,cls表示需要實例化的類,此參數在實例化時由Python解釋器自動提供 __new__方法接受的參數雖然也是和__init__一樣,但__init__是在類實例創建之後調用,而 __new__方法正是創建這個類實例的方法 # ----------------------------------------- 1.__init__ 通常用於初始化一個新實例,控制這個初始化的過程,比如添加一些屬性, 做一些額外的操作,發生在類實例被創建完以後。它是實例級別的方法。 2.__new__ 通常用於控制生成一個新實例的過程。它是類級別的方法。 三、__new__ 的作用 依照Python官方文檔的說法,__new__方法主要是當你繼承一些不可變的class時(比如int, str, tuple), 提供給你一個自定義這些類的實例化過程的途徑。還有就是實現自定義的metaclass __init__方法通常用在設置不變數據類型的子類,註意在使用new方法的時候,調用了父類的new方法,並且返回了這個值,使用return語句 當不使用return的時候,那麽此值會變成為None,也就是默認情況下返回值為None class PositiveInteger(int): def __new__(cls, value): return super(PositiveInteger, cls).__new__(cls, abs(value)) i = PositiveInteger(-3) print(i) # __str__ 如果要把一個類的實例變成str,就需要實現特殊方法__str__() class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender def __str__(self): return (Person: %s, %s) % (self.name, self.gender) 盡管str(),repr()和``運算在特性和功能方面都非常相似,事實上repr()和``做的是完全一樣的事情,它們返回的是一個對象的“官方”字符串表示, 也就是說絕大多數情況下可以通過求值運算(使用內建函數eval())重新得到該對象,但str()則有所不同。str()致力於生成一個對象的可讀性好的字符串表示, 它的返回結果通常無法用於eval()求值,但很適合用於print語句輸出。需要再次提醒的是,並不是所有repr()返回的字符串都能夠用 eval()內建函數得到原來的對象。 也就是說 repr() 輸出對 Python比較友好,而str()的輸出對用戶比較友好。雖然如此,很多情況下這三者的輸出仍然都是完全一樣的。 str與repr區別: 1、python中str函數通常把對象轉換成字符串,即生成對象的可讀性好的字符串,一般在輸出文本時使用,或者用於合成字符串。str的輸出對用戶比較友好適合print輸出。 2、pyton中repr函數將一個對象轉成類似源代碼的字符串,只用於顯示。repr的輸出對python友好,適合eval函數得到原來的對象。 3、在類中實現__str__和__repr__方法,就可以得到不同的返回 #__setitem__ 安裝索引賦值 # __getitem__ 按照索引獲取值 class A: def __init__(self): self.dict_num = {} def __setitem__(self, key, value): self.dict_num[key] = value return self.dict_num def __getitem__(self, item): return self.dict_num[item] a = A() a[name] = jack print(a.dict_num) print(a.dict_num[name]) 》》》{name: jack} 》》》jack # __len__ 獲取長度 如果一個類表現的像一個list,要獲取多少個元素與,就得用len()函數 要讓len()函數正常工作,類必須提供一個特殊的方法__len__(),它返回元素的個數 class Name(object): def __init__(self, *args): self.names = args def __len__(self): return len(self.names) n = Name(1, 2, 3) print(len(n)) # __cmp__ 比較運算 對int、str等內置數據類型排序時, Python的sorted()按照默認的比較函數cmp排序,但是,如果對一組student類的實例排序時,就必須提供我們自己的特殊方法__cmp__ # __add_ 加運算 # __sub__ 減運算 # __mul__ 乘運算 #__div__ 除運算 #__mod__ 求余運算 # __pow__ 乘方 # __call__() ·對象通過提供一個__call__(self, *args, **kwargs)方法可以模擬 函數的行為,如果一個對象提供該方法,可以向函數一樣去調用它 # __module__ 表示當前操作的對象在那個模塊 # __class__ 表示當前操作的對象的類是什麽 # isinstance(obj, cls) 檢查obj是否是類cls的對象 class Foo(object): pass f = Foo() isinstance(f, Foo) # issubclass(sub, super) 檢查sub類是否是super類的派生類 class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo) # ######################################## 靜態字段(屬於類的字段) 動態字段(self.對象) ·屬於類 ·self.屬於對象 ·訪問類.變量名,訪問 靜態類不能訪問動態字段 實例化的對象可以訪問靜態字段 ·盡量不要用實例化後的對象訪問靜態字段,造成歧義 # ####################################### 靜態方法:屬於類 @staticmethod,去掉self創建靜態方法 為什麽要使用靜態方法: ·Python 可以直接使用靜態方法,而避免了去實例化一個對象。實例化對象需要消耗資源的,靜態方法避免了這一切。 實例化後的對象可以訪問動態方法 靜態類不能訪問動態方法啊、 ***************************************** Python的靜態方法和類成員方法都可以被類或實例訪問,兩者概念不容易理清,但還是有區別的: 1)靜態方法無需傳入self參數,類成員方法需傳入代表本類的cls參數; 2)從第1條,靜態方法是無法訪問實例變量的,而類成員方法也同樣無法訪問實例變量,但可以訪問類變量; 3)靜態方法有點像函數工具庫的作用,而類成員方法則更接近類似Java面向對象概念中的靜態方法。 # ####################################### 特性/屬性: @property把方法訪問形式變成字段的訪問形式 方法 hb.bar() 字段 hb.bar ·將類方法轉換為只讀屬性 ·重新實現一個屬性的setter和getter方法 # ###################################### 私有字段:self.__thailand = flag 類外部無法訪問 AttributeError: A object has no attribute __thailand 私有方法:def __print(): print(hello world) *************************************** class A: this_num = 123 def __init__(self, name, flag): self.__thailand = flag self.name = name def show(self): print(self.__thailand) @staticmethod def __print(): print(hello world) def show_print(self): self.__print() if __name__ == __main__: a = A(sx, True) print(a.name) a.show() a.show_print() *************************************** # 直接在外部調用私有方法字段 a._A__print() # ##################################### # 只讀只寫特性 class RW(object): def __init__(self, name): self.__name = name @property def show_name(self): """可讀""" return self.__name @show_name.setter def show_name(self, value): """可寫""" self.__name = value if __name__ == __main__: jack = RW(JACK) print(jack.show_name) jack.show_name = KEVIN print(jack.show_name) # #################################### 垃圾回收機制 Python 采用垃圾回收機制來清理不再使用的對象;Python 提供gc模塊釋放 不再使用的對象,Python 采用‘引用計數’ 的算法方式來處理回收, 即:當某個對象在其作用域內不再被其他對象引用的時候,Python 就自動清除對象; Python 的函數collect()可以一次性收集所有待處理的對象(gc.collect()) # ####################################__del__”就是一個析構函數了,當使用del 刪除對象時,會調用他本身的析構函數,另外當對象在某個作用域中調用完畢,在跳出其作用域的同時析構函數也會被調用一次,這樣可以用來釋放內存空間。 __del__()也是可選的,如果不提供,則Python 會在後臺提供默認析構函數 註:一般用不上,使用場景: 操作文件的時候,打開文件獲取的句柄,打開之後一直沒釋放 釋放後銷毀,釋放的動作可以卸載del裏面 __del__:永遠是最後執行的 # #################################### __call__方法 對象通過提供__call__(slef, [,*args [,**kwargs]])方法可以模擬函數的行為,如果一個對象x提供了該方法,就可以像函數一樣使用它, 也就是說x(arg1, arg2...) 等同於調用x.__call__(self, arg1, arg2) 。模擬函數的對象可以用於創建防函數(functor) 或代理(proxy) class F: def __init__(self): pass def __call__(self): print(call) if __name__ == __main__: f1 = F() # f1為實例化的對象 f1() # 默認執行Call方法 # #################################### 類的繼承 super()函數 super() 函數用於調用下一個父類(超類)並返回該父類實例的方法。 super 是用來解決多重繼承問題的,直接用類名調用父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查找順序(MRO)、重復調用(鉆石繼承)等種種問題。 註意:super繼承只能用於新式類,用於經典類時就會報錯。 新式類:必須有繼承的類,如果沒什麽想繼承的,那就繼承object 普通繼承與super繼承 它們的內部運行機制不一樣,這一點在多重繼承時體現得很明顯。在super機制裏可以保證公共父類僅被執行一次,至於執行的順序,是按照mro進行的(E.__mro__)。 註意:super繼承只能用於新式類,用於經典類時就會報錯。 新式類:必須有繼承的類,如果沒什麽想繼承的,那就繼承object 經典類:沒有父類,如果此時調用super就會出現錯誤:『super() argument 1 must be type, not classobj』 # #################################### python的多態指同一個方法,不通的行為。對於不同的類,可以有同名的兩個或多個方法。取決於這些方法分別應用到哪些類,他們可以有不同的行為。 當子類和父類都存在相同的 print_title()方法時,子類的 print_title() 覆蓋了父類的 print_title(),在代碼運行時,會調用子類的 print_title()     這樣,我們就獲得了繼承的另一個好處:多態。     多態的好處就是,當我們需要傳入更多的子類,例如新增 Teenagers、Grownups 等時,我們只需要繼承 Person 類型就可以了, 而print_title()方法既可以直不重寫(即使用Person的),也可以重寫一個特有的。這就是多態的意思。調用方只管調用,不管細節,而當我們新增一種Person的子類時, 只要確保新方法編寫正確,而不用管原來的代碼。這就是著名的“開閉”原則: 對擴展開放(Open for extension):允許子類重寫方法函數 對修改封閉(Closed for modification):不重寫,直接繼承父類方法函數 # #################################### 多態性是指具有不同功能的函數可以使用相同的函數名,這樣就可以用一個函數名調用不同內容的函數。 、在面向對象方法中一般是這樣表述多態性:向不同的對象發送同一條消息,不同的對象在接收時會產生不同的行為(即方法)。 也就是說,每個對象可以用自己的方式去響應共同的消息。所謂消息,就是調用函數,不同的行為就是指不同的實現,即執行不同的函數 其實大家從上面多態性的例子可以看出,我們並沒有增加上面新的知識,也就是說Python本身就是支持多態性的,這麽做的好處是什麽呢? (1)增加了程序的靈活性   以不變應萬變,不論對象千變萬化,使用者都是同一種形式去調用,如func(animal) (2)增加了程序額可擴展性   通過繼承animal類創建了一個新的類,使用者無需更改自己的代碼,還是用func(animal)去調用 多態:同一種事物的多種形態,動物分為人類,豬類(在定義角度) 多態性:一種調用方式,不同的執行效果(多態性) # #################################### 多重繼承 除了從一個父類繼承外,Python允許從多個父類繼承,稱為多重繼承。 多重繼承的繼承鏈就不是一棵樹了,它像這樣: class A(object): def __init__(self, a): print init A... self.a = a class B(A): def __init__(self, a): super(B, self).__init__(a) print init B... class C(A): def __init__(self, a): super(C, self).__init__(a) print init C... class D(B, C): def __init__(self, a): super(D, self).__init__(a) print init D... # #################################### “新式類”和“經典類”的區分在Python 3之後就已經不存在, 在Python 3.x之後的版本,因為所有的類都派生自內置類型object(即使沒有顯示的繼承object類型),即所有的類都是“新式類”。 經典類和新式類的區別: ·繼承object,新式類 ·沒有object,經典類 新式類兼容經典類的功能 新式類修復好了經典類的一個bug(面臨經典類多繼承的問題) 1.類是可以多繼承的 class A: def __init__(self): print(A class) def save(self): print(A save) class B(A): def __init__(self): print(B class) class C(A): def __init__(self): print(C class) def save(self): """方法重寫""" print(C save) class D(B, C): def __init__(self): print(D class) # D這時應該繼承C的save方法 # 經典類從B 到 A 再到C的繼承S if __name__ == __main__: D = D() D.save() 經典類是深度優先 經典類是廣度優先 正確:先B再C再搜A # #################################### 抽象類: 由於python 沒有抽象類、接口的概念,所以要實現這種功能得abc.py 這個類庫 子類繼承抽象類,如果沒有抽象類的方法,則報錯。 抽象類+抽象方法 = 接口(用作代碼規範) from abc import ABCMeta, abstractmethod class Super(metaclass=ABCMeta): def delegate(self): self.action() @abstractmethod def action(self): pass # X = Super() # TypeError: Can‘t instantiate abstract class Super with abstract methods action # 帶有抽象方法的類不能繼承(即,不能通過它來創建一個實例) class Sub(Super): # def action(self): # print(‘spam‘) @staticmethod def show_time(): print(hello) # TypeError: Can‘t instantiate abstract class Sub with abstract methods action # 子類繼承抽象類,如果沒有抽象類的方法,則報錯。 s = Sub() # s.action() s.show_time()

異常處理

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

***************************************

多個異常捕捉:
try:
    xxxxx
except (ValueError, NameError)as e:
    print(e)

捕捉所有異常
try:
    xxxxx
except Exception as e:
    print(e)

finally:
    無論出現異常都會執行

***************************************
自定義異常:
class MyException(Exception):

    def __init__(self, msg):
        self.error = msg

    def __str__(self, *arg, **kwargs):
        return self.error

class DatabaseException(Exception):  
    def __init__(self,err=數據庫錯誤):  
        Exception.__init__(self,err)  
        

***************************************
手動觸發異常:
raise MyException(my error)

Python學習筆記之面對象與錯誤處理