面向對象編程是一種編程方式,使用 「類」 和 「對象」 來實現,因此,面向對象編程其實就是對 「類」 和 「對象」 的使用。類就是一個模板,模板裏能夠包含多個方法(函數),方法裏實現各類各樣的功能,對象則是根據模板建立的實例,經過實例,對象能夠執行類中的方法,每一個對象都擁有相同的方法,但各自的數據可能不一樣。java
在Python中,定義類是經過class
關鍵字,class
後面緊接着是類名,類名一般是大寫開頭的單詞,緊接着是('要繼承的類名')
,表示該類是從哪一個類繼承下來的,能夠有多個父類(基類),一般若是沒有合適的繼承類,就使用object
類,這是全部類最終都會繼承的類,也能夠不寫。python
class F1(object): def __init__(self,name,age): self.name = name self.age = age f1 = F1('python',27) 上面的這個__init__()叫作初始化方法(或構造方法), 在類實例化時,這個方法(雖然它是函數形式,但在類中就不叫函數了,叫方法)會自動執行,
進行一些初始化的動做,因此咱們這裏寫的__init__(self,name,age)就是要在建立一個角色時給它設置這些屬性。
參數self有什麼用呢?
1.在內存中開闢一塊空間指向f1這個變量名
2.實例化F1這個類首先執行其中的__init__()方法,至關於F1.__init__(f1,'python',27),是爲了把'python',27這2個值跟剛開闢的f1關聯起來,由於關聯起來後,你就能夠直接f1.name, f1.age 這樣來調用啦。因此,爲實現這種關聯,在調用__init__方法時,就必須把f1這個變量也傳進去,不然__init__不知道要把那2個參數跟誰關聯,self其實就是實例化對象f1被看成參數傳遞了。
3.因此這個__init__(…)構造方法裏的,self.name = name , self.age = age 等等就是要把這幾個值存到f1的內存空間裏。 程序員
面向對象有3大特性,首先咱們來講第一個特性,封裝,封裝通常是經過在類中封裝數據,而經過對象或者self獲取。和其餘面向對象的語言相似,也是經過構造函數來進行數據封裝。下面來看一下代碼。 數據庫
class A: def __init__(self,name): # 構造函數,初始化數據, self.name=name # 封裝數據 def f1(self): print(self.name) # 經過self間接獲取封裝的數據 a=A('json') # 至關於A.__init__(a,'json')將'json'封裝到a中的name屬性中 print(a.name) # 直接調用a對象的name屬性 a.f1() # python會把a看成參數傳遞給a.f1(a),因此print(a.name)
還有一種封裝的方式,使用私用的屬性來封裝數據,看一下具體的用法,編程
class A: name='Jason' __age=18 # 私有類屬性 def __init__(self): self.__like='soccer' # 私有實例屬性 self.hobby='kkkk' def f1(self): print(self.__age) # 私有類屬性,私有實例屬性只能被類中的方法調用 print(self.__like) # A.__age # 外部獲取不到私有類屬性,數據被封裝起來 a=A() # soccer a.f1() # 18 print(a.hobby)
複雜的封裝(必定要搞清楚): 將類封裝進對象中 json
class c1: def __init__(self,name,obj): self.name = name self.obj = obj class c2: def __init__(self,name,age): self.name = name self.age = age def show(self): print(self.name) class c3: def __init__(self,a1): self.money = 123 self.aaa = a1 c2_obj = c2('aa',12) # 將字符串'aa',數字12封裝到c2_obj.name和c2_obj.age中 c1_obj = c1('python',c2_obj) # 將字符串'python'封裝到c1_obj.name中,將c2_obj中的屬性c2_obj.name,c2_obj.age封裝到c1_obj.obj中 c3_obj = c3(c1_obj) # 將c1_obj中的全部屬性,包括(c2_obj的所全部方法和屬性) print(c3_obj.aaa.obj.name) #c3類中找到c2類中的屬性 ret = c3_obj.aaa.obj.show() #c3類中找到c2類中的方法執行並接收返回值 print(ret)
繼承的本質是將父類中的方法所有複製一份到子類中。Python裏面的繼承能夠多繼承,經過繼承,能夠得到父類的功能,繼承的時候,若是父類中有重複的方法,優先找本身c#
經過繼承建立的新類稱爲「子類」或「派生類」。被繼承的類稱爲「基類」、「父類」或「超類」。
函數式編程
(1)、Python的類能夠繼承多個類,Java和C#中則只能繼承一個類函數
(2)、Python的類若是繼承了多個類,那麼其尋找方法的方式有兩種,分別是:深度優先和廣度優先spa
經典類和新式類,從字面上能夠看出一個老一個新,新的必然包含了跟多的功能,也是以後推薦的寫法,從寫法上區分的話,若是 當前類或者父類繼承了object類,那麼該類即是新式類,不然即是經典類。
繼承的執行過程例子:
class A: def f(self): print('a') class B: def f(self): print('b') def f1(self): print('bbbb') class C(A,B): def f1(self): print('c') cc=C() cc.f() # 結果爲a,在C類中沒有f()這個方法時,繼承時A基類寫在前面,因此優先找A類中的f()方法 cc.f1() # 結果爲c,在C類中有f1()方法,則優先執行本身的方法
下面是重點和難點,在其餘源碼都是這麼幹的
class A: def bar(self): print('bar') self.f1() class B(A): def f1(self): print('b') class C(): def f1(self): print('c') class D(B): def f1(self): print('d') class E(C,D): pass d=D() d.bar()
上述繼承的執行過程:
(3)、除了繼承方法,還能夠繼承父類的構造函數
# 繼承構造方法 class A: def __init__(self): self.name='jason' class B(A): def __init__(self): self.age='16' super(B,self).__init__() # A.__init__(self) #另外一種繼承構造函數的方法 d=B()
(4)、強制使用父類中的方法(很是有用)使用:super(子類類名,self).父類中的方法
class C1: def f1(self): print('c1.f1') return 123 class C2(C1): def f1(self): # 主動執行父類的f1方法 ret = super(C2,self).f1() print('c2.f1') return ret # C1.f1(self) 第二種方法,主動執行父類的方法,不經常使用 obj = C2() obj.f1()
Pyhon不支持Java和C#這一類強類型語言中多態的寫法,python自己就是支持多態的,因此在Python面向對象裏面討論多態並無什麼意義,其Python崇尚「鴨子類型」。
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)
在java,c#中定義參數是須要強制定義一個參數是什麼類型的參數,相似下面的代碼
class A: pass class B(A): pass class C(A): pass # arg參數:必須是A類型或A的子類 def func(A arg): print(arg) # obj = B() # obj = C() obj = A() func(obj)
以上就是本節對於面向對象初級知識的介紹,總結以下:
問答專區
問題一:什麼樣的代碼纔是面向對象?
答:從簡單來講,若是程序中的全部功能都是用 類 和 對象 來實現,那麼就是面向對象編程了。
問題二:函數式編程 和 面向對象 如何選擇?分別在什麼狀況下使用?
答:須知:對於 C# 和 Java 程序員來講不存在這個問題,由於該兩門語言只支持面向對象編程(不支持函數式編程)。而對於 Python 和 PHP 等語言卻同時支持兩種編程方式,且函數式編程能完成的操做,面向對象均可以實現;而面向對象的能完成的操做,函數式編程不行(函數式編程沒法實現面向對象的封裝功能)。
因此,通常在Python開發中,所有使用面向對象 或 面向對象和函數式混合使用
面向對象的應用場景:
class SqlHelper: def __init__(self, host, user, pwd): self.host = host self.user = user self.pwd = pwd def 增(self): # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接 # do something # 關閉數據庫鏈接 def 刪(self): # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接 # do something # 關閉數據庫鏈接 def 改(self): # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接 # do something # 關閉數據庫鏈接 def 查(self): # 使用主機名、用戶名、密碼(self.host 、self.user 、self.pwd)打開數據庫鏈接 # do something # 關閉數據庫鏈接# do something
如:張3、李4、楊五,他們都有姓名、年齡、血型,但其都是不相同。即:屬性個數相同,但值不相同
class Person: def __init__(self, name ,age ,blood_type): self.name = name self.age = age self.blood_type = blood_type def detail(self): temp = "i am %s, age %s , blood type %s " % (self.name, self.age, self.blood_type) print temp zhangsan = Person('張三', 18, 'A') lisi = Person('李四', 73, 'AB') yangwu = Person('楊五', 84, 'A')
問題三:類和對象在內存中是如何保存?
答:類以及類中的方法在內存中只有一份,而根據類建立的每個對象都在內存中須要存一份,大體以下圖:
如上圖所示,根據類建立對象時,對象中除了封裝 name 和 age 的值以外,還會保存一個類對象指針,該值指向當前對象的類。
當經過 obj1 執行 【方法一】 時,過程以下: