一、編程范式
1、定義:簡單說就是程式員為了解決一系列編程問題而使用的編程套路,比如面向程序式編程,面向物件式編程,函式式編程,都屬于編程范式,
2、面向程序編程:為計算機執行流程定義了一系列的函式,計算機將順序執行完成任務,
-
- 優點:便捷、快速完成編程任務
- 缺點:維護困難,改一處,別的依賴的代碼也需要更改,
- 使用場景:適合在今后作業中無需更改的地方使用,比如資料庫連接,如果公司以后也沒有用oracle,只用mysql資料庫,那么這里就可以用面向程序式編程,
3、面向物件編程(OOP ):利用類和物件創建各種模型,來實作對真是世界的描述,
-
- 優點:維護擴展更簡單,大大提高程式開發效率,使他人更容易理解你的代碼邏輯,團隊開發更從容,
- 缺點:效率比面向程序低,需要語言特定支持,
- 類(Class): 這是對現實世界的一類物件的抽象總結,比如人類,動物類等等,里面包含了這類事物的共性功能(方法)和屬性,
- 物件(object):某一個類(Class)的具象化的表達,比如人類,那么對應到物件就是某個具體的人,
- 總結:世界萬物皆是物件,所有物件皆屬于某個品類
二、面向物件的特性
1、封裝(Encapsulation):即隱藏物件的屬性和實作細節,僅對外公開介面,控制在程式中屬性的讀和修改的訪問級別,這使得從外界看來封裝的代碼是不透明的,不需要關心內部發生的事情,大大降低了使用的復雜性,
2、繼承(Inheritance):一個類可以派生出子類,子類可以繼承父類的方法和屬性,也可以對其進行改寫以適應新的物件,這個程序就是繼承(后面詳細解釋)
3、多型(polymorphism):簡單說是“一個介面,多種實作”就是多型,因為子類繼承了父類,并且可能對父類中的共有方法進行更改,使得同個類的物件表現出多種形態,并且支持使用父類參考來統一呼叫,這就對外界實作了統一的呼叫介面,又大大降低了代碼的復雜性,比如生活中的電器都是很復雜的,但是使用者不需要了解其原理,只需要讀說明書掌握使用方法即可,使用多型的目的就是介面的重用,代碼如下:
# 面向物件 class Animel: def __init__(self, name): self.name = name @staticmethod def animel_eating(self): self.eating() class Mouse(Animel): def eating(self): print("%s 開始吃飯了.." % self.name) print("一桶一桶的吃...") class Duck(Animel): def eating(self): print("%s 開始吃飯了.." % self.name) print("一口一口的吃...") m = Mouse("米老鼠") d = Duck("唐老鴨") Animel.animel_eating(m) Animel.animel_eating(d)
4、為什么使用面向物件編程?
-
- 編程中要盡量不寫重復的代碼,因為你的程式需要經常修改,如果重復代碼很多,那么需要多處修改,導致程式千瘡百孔,不穩定,開發效率低下,所以將公用的代碼寫在一處勢在必行,
- 面向程序將公用代碼寫在一個函式里然后多處呼叫就是很好的方法,
- 面向物件比面向程序更有利于組織和擴展代碼,大大提升效率,
5、建構式:實體化類時做初始化的作業,用__init__(self)定義,同時傳遞一個self記憶體地址,代表此物件的記憶體地址賦給自己
6、解構式:物件釋放銷毀的時候自動呼叫,通常做一些收尾的作業,比如關閉打開的資料庫連接等,用__del__(self)定義,不能傳遞引數給他,因為他是自動呼叫的,
7、物件的屬性:
-
- 在構造方法中被賦值,將物件屬性的值通過構造方法引數self賦值給該物件,
- 作用域是物件本身,物件之間不能公用,
- 物件的屬性的作用是記錄屬于物件的特定的值,每個物件這個值都可能不一樣,
8、類的屬性:
-
- 可以通過類名直接呼叫,也可以通過物件呼叫,他們的值是一樣的,
- 如果物件屬性和類屬性同名則先找物件屬性再找類屬性
- 如果修改了類屬性的值,則多個物件都會改變其值,除非該物件有一個同名的物件屬性(會優先呼叫物件屬性)
- 類的屬性的作用是記錄一些類的公共屬性值,節省資源開銷,比如國籍設定成中國,就是這個類的所有物件都是中國人,不需要每個物件都設定成中國,
9、類的方法:因為方法都是統一在類中定義而且每一個繼承該類的物件都有相同的方法,所以無需每個物件都存方法,只需要存一份類方法即可,每一個類方法都默認傳遞一個self變數,告訴此類方法呼叫它的是哪一個物件,
10、私有屬性:不允許讓物件外界直接通過物件.屬性名修改值,將屬性名標記為__開頭,就無法在外界訪問了,只能通過類內部的方法間接訪問
11、私有方法:同私有屬性,
12、靜態方法:在方法頭部用@staticmethod裝飾器定義,靜態方法無需傳遞self引數,名義上屬于類里的方法,但是他無法訪問任何物件和類的屬性,一般將其作為工具方法使用,比如某個方法無需使用初始化的屬性值,僅作為功能使用,比如os包中的很多方法,都是相互獨立的,相當于一個同類方法的工具包組合,
13、類方法:在方法頭部用@classmethod裝飾器定義,可以訪問類屬性,不能訪問物件屬性
14、屬性方法:在方法頭部用@property裝飾器定義,把一個方法變成一個靜態屬性,隱藏了實作細節,通過物件.屬性方法呼叫,不帶括號,不能直接傳引數,需要用到@屬性方法名.setter定義一個同名的賦值方法未其賦值,如下代碼:
class A(object): def __init__(self): # 私有屬性,通過屬性方法訪問和賦值 self.__name = "" # 屬性值 @property def a(self): print("Hello %s" % self.__name) # 設定值 @a.setter def a(self, name): self.__name = name # 洗掉 @a.deleter def a(self): del self.__name print("已經洗掉") a1 = A() #賦值 a1.a = "tangwei" #讀值 a1.a # 洗掉以后就無法再訪問該物件屬性 # del a1.a
15、__doc__:列印類頭部用"""描述"""的描述資訊
16、__module__:當前操作的物件在哪個模塊,也就是他所屬于的包路徑
17、__class__:當前操作的物件屬于哪個類
18、__call__:如果在類中定義了__call__()方法,則可以通過“實體(傳任何位置和關鍵詞引數)”來呼叫,
19、__dict__:查看類或物件的所有成員,如果通過類呼叫則顯示所有類的屬性和元資料,而通過物件呼叫則顯示所有的屬性和值,以字典形式回傳,
20、__str__:如果類方法中定義了__str__()方法,則使用print列印此類物件的時候會按定義的方法體執行,如果未定義__str__()則列印此物件的記憶體地址,
21、__new__:new方法是每一個類中自帶的方法,在物件實體化時,先于__init__()方法被執行,如果需要在實體化之前需要做的步驟可以重寫new方法
22、__metaclass__:定義一個類怎樣用自己的方式來創建它,代碼如下:

三、類的繼承:
1、通過定義class 類名(所要繼承的父類),來繼承一個父類,
2、對父類方法重寫:如果子類不重寫父類的方法,則默認呼叫父類中的定義的同名方法,如果子類重寫了某個方法,則呼叫子類中定義的方法,
3、對父類構造方法重寫:可以傳遞該子類的特有的屬性值,但是又不影響其他子類,注意:在子類重寫的構造方法體內部要呼叫父類構造方法先初始化父類,格式如下
class A: def __init__(self, name, age): self.name = name self.age = age def eating(self): print("%s 吃飯了..." % self.name) class B(A): def __init__(self, name, age, money): # A.__init__(self, name, age) # 此寫法同上,但是更方便,萬一是多繼承就不需要寫多個init初始化父類了, super(B, self).__init__(name, age) self.money = money def eating(self): print("%s 不吃飯了...賬戶只有:%s元" % (self.name, self.money)) b = B("tangwei", 22, 10) b.eating()
4、多繼承的情況,一個子類既繼承A類又繼承B類,那么在初始化的時候只按繼承順序初始化第一個類的建構式,super會自行按繼承順序判斷(先B還是先C按照書寫順序由左到右),如果要初始化多個父類的構造方法就只能用__init__()一個一個初始化,不能用super如下,實際編碼實踐中,盡量避免多繼承,盡量避免多繼承的時候手動去實體化父類,盡量避免父類實體化時傳遞具體引數,父類的作用主要是用來繼承,并且主要代碼和初始化屬性值在子類中:
class A: def __init__(self, name, age): self.name = name self.age = age def eating(self): print("%s 吃飯了.." % self.name) class B: def __init__(self, n1, n2, n3): self.n3 = n3 pass def slopping(self, obj): print("%s在購物 賬戶還有%s元" % (obj.name, self.n3)) class C(A, B): def __init__(self, name, age, money): A.__init__(self, name, age) B.__init__(self, name, age, money) self.money = money def eating(self): print("%s 不吃飯了...賬戶只有:%s元" % (self.name, self.money)) c = C("tangwei", 22, 10) c.slopping(c)
5、多級繼承,D繼承B和C,而B和C又繼承A,初始化的時候構造方法按“廣度優先”順序先初始化B和C(先B還是先C按照書寫順序由左到右),再初始化A,(注意python2.7如果未繼承object物件為經典模式則菜用深度優先,即先初始化B再A再C,如果有繼承object物件則為廣度優先,python3.0都是廣度優先)
6、所有的類都是繼承object類,object類又繼承Type類,通過Type類的可以手動組合出一個類的物件,如下:
def __init__(self, name): self.name = name def get_name(self): print(self.name) my_obj = type("MyObj", (object,), {"get_name": get_name, "__init__": __init__}) my_obj("tangwei").get_name()
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/152401.html
標籤:Python
上一篇:python基礎
