面向對象編程

類和對象

1.什麼叫類: 類是一種數據結構, 就比如一個模型, 該模型用來表述一類事務(事務即數據和動做的結合體), 用它來生產真實的物體(實例).python

2.什麼叫對象: 睜開眼, 你看到的一切的事物都是一個個的對象, 你能夠把對象理解爲一個具體的事物(事物即數據和動做的結合體)算法

3.類與對象的關係: 對象都是由類產生的編程

4.什麼叫實例化:由類生產對象的過程叫實例化,類實例化的結果就是一個對象,或者叫作一個實例(實例=對象)數據結構

面向對象設計與面向對象編程

面向對象設計:將一類具體事物的數據和動做整合到一塊兒,即面向對象設計socket

#用基於結構化的語言來實現面向對象設計
def wang(name,genle,type):
    def jiao(dog):
        print("%s正在叫"%dog["name"])
    def chi(dog):
        print("%s正在吃"%dog["name"])
    def init(name,genle,type):
        dog1 ={
            "name":name,
            "genle":genle,
            "type":type,
            "jiaoa":jiao,
            "chi":chi
        }
        return dog1
    return init(name,genle,type)

d1 = wang("xiaoming","gong","tianyuanquan")
print(d1)
d1["jiaoa"](d1)

面向對象編程: 用定義類 + 實例/對象的方式去實現面向對象的設計函數

class Chinese:
    name = "abc"
    def chifan(self,x):
        print("姓名:%s喜歡吃%s"%(self.mingzi,x))
    def shuijiao(self):
        print("nianling:%s"%self.nianling)
    def __init__(self,name,age):
        self.mingzi = name
        self.nianling = age
f1 = Chinese("xiaoming",18)
f1.chifan("eat")
f1.shuijiao()

類的聲明

1 大前提:
 2 1.只有在python2中才分新式類和經典類,python3中統一都是新式類
 3 2.新式類和經典類聲明的最大不一樣在於,全部新式類必須繼承至少一個父類
 4 3.全部類甭管是否顯式聲明父類,都有一個默認繼承object父類(講繼承時會講,先記住)
 5 在python2中的區分
 6 經典類:
 7 class 類名:
 8     pass
 9 
10 經典類:
11 class 類名(父類):
12     pass
13 
14 在python3中,上述兩種定義方式全都是新式類


python3中聲明類
1 '''
 2 class 類名:
 3     '類的文檔字符串'
 4     類體
 5 '''
 6 
 7 #咱們建立一個類
 8 class Data:
 9     pass
10 
11 #用類Data實例化出一個對象d1
12 d1=Data()

類的屬性

類有數據屬性跟函數屬性(又稱方法屬性)ui

class Chinese:
    name = "abc"
    def chifan(self,x):
        print("姓名:%s喜歡吃%s"%(self.mingzi,x))
    def shuijiao(self):
        print("nianling:%s"%self.nianling)
    def __init__(self,name,age):#爲實例定製數據屬性,可使用類的一個內置方法__init__()該方法,在類()實例化是會自動執行
        self.mingzi = name
        self.nianling = age
f1 = Chinese("alex",18)   #類的實例化,至關於運行__init__函數,將參數傳給__init函數體中對應的位置,生成一個字典,其中self即表明f1自身
f1.chifan("eat")#經過.調用類的屬性,首先會在__init__做用域內查找,若沒找到會到類的屬性中尋找,實例化生成的對象只具有數據屬性,調用的方法爲類的屬性並不是生成的對象所具有的屬性
f1.shuijiao()

  有兩種方法查看類的屬性spa

  dir(類名):  查出的是一個名字列表設計

  類名.__dict__:查出的是一個字典, key爲屬性名, value爲屬性值code

1 class Chinese:
2     name = "abc"
3     def chifan(self):
4         print(123)
5     def shuijiao(self):
6         print("456")
7 print(Chinese.name)#打印的是name屬性對應的內容
8 print(Chinese.__dict__)#顯示結果是一個字典,包含類的全部屬性:屬性值 
9 print(dir(Chinese))#顯示結果是一個列表,包含類(包含內建屬性在內的)全部的屬性名

  特殊的類屬性

  __name__,類的名字

  __doc__,查看類的文檔字符串

  __module__, 類定義所在的模塊__class__, 實例C對應的類(僅新式類中)

  類的方法屬性的增刪改查

 

 1 class math:
 2     country = "China"
 3     def chi(self,food):
 4         print("%s正在吃%s"%(self.mingzi,food))
 5     def __init__(self,name):
 6         self.mingzi = name
 7 f1 = math("alex")
 8 print(math.country)    #查看
 9 # print(dir(math))
10 # print(math.__dict__)
11 def yundong(self,hobby):#增長
12     print("%s正在%s"%(self.mingzi,hobby))
13 math.aihao = yundong
14 #print(math.__dict__)
15 f1.aihao("打籃球")
16 #del math.chi
17 #print(math.__dict__)
18 def aichi(self,food):#修改
19     print("%s很開心的吃%s"%(self.mingzi,food))
20 math.chi =aichi
21 f1.chi("")

 

類的數據屬性的增刪改查

 1 class math:
 2     country = "China"
 3     def chi(self,food):
 4         print("%s正在吃%s"%(self.mingzi,food))
 5     def __init__(self,name,age):
 6         self.mingzi = name
 7         self.nianling = age
 8 
 9 f1 = math("xiaoming",18)
10 print(f1.__dict__)   #查看
11 f1.mingzi = "eric" #修改
12 print(f1.__dict__)
13 f1.xingbie = ""  # 增長
14 del f1.mingzi    #刪除
15 print(f1.__dict__

類屬性與對象(實例)屬性

  1.實例化會自動觸發__init__函數的運行,最後返回一個值即實例, 咱們要找的實例屬性就存放            在 __init__函數的局部做用域裏

  2.類有類的屬性字典, 就是類的做用域, 實例有實例的屬性字典, 即實例的做用域

  3.綜上, 一個點表明一層做用域, obj.x先從本身的做用域找, 本身找不到去外層的類的字典中去         找, 都找不到, 就會報錯

  4.在類中沒有使用點的調用, 表明調用全局變量

1 country = "China"
2 class Chinese:
3     country = "japan"
4     def __init__(self,name):
5         self.mingzi = name
6         print(country)#打印的是普通變量country,非類結構中的變量,要調用類中的變量要用"."調用
7 f1 = Chinese("tom")

靜態屬性,類方法,靜態方法

 1 class Room:
 2     arg = 123
 3     def __init__(self,name,weith,lenth,height):
 4         self.mingzi = name
 5         self.kuandu = weith
 6         self.changdu = lenth
 7         self.gaodu = height
 8     @property#靜態屬性,將實例化對象變成類的數據屬性,將該方法封裝起來,做用可隱藏邏輯代碼,直接用實例+"."調用該方法
 9     def tiji(self):
10         return self.kuandu*self.changdu*self.gaodu
11 
12     @classmethod#類方法,專門供類使用,與實例無關,類方法只能訪問類相關的屬性,不能訪問實例屬性,與實例無關
13     def tell_info(cls,x):#默認參數cls不可變,爲類名,後邊可接參數
14         print(cls)
15         print("------>",Room.arg,x)
16 
17     @staticmethod   #靜態方法 ,類的靜態方法,沒有默認參數,不能使用類變量和實例變量
18     def op(x,y,z):
19         print(x,y,z)
20 f1 = Room("tom",10,50,20)
21 print(f1.tiji)#因爲用了property方法封裝該方法(已變成數據屬性),故可直接調用該數據屬性
22 Room.tell_info("abc")
23 Room.op(1,2,3)     #類傳參數能夠調用
24 f1.op(1,2,3)      #實例傳參數能夠調用

組合

做用:   作關聯

 1 class School:
 2     def __init__(self,name,difang):
 3         self.name = name
 4         self.difang = difang
 5 class Teacher:
 6     def __init__(self,name,sex,school):
 7         self.name = name
 8         self.sex = sex
 9         self.school = school
10 class Lesson:
11     def __init__(self,name,price,period,techer):
12         self.name = name
13         self.price = price
14         self.period = period
15         self.techer = techer
16 
17 p1 = School("baidu","北京")
18 t1 = Teacher("tom","male",p1)#將p1對象直接添加到t1對象屬性中
19 L1 = Lesson("python班",10000,"4month",t1)

面向對象編程三大特性

(1)類的繼承: 類的繼承跟現實生活中的父,子,孫,重孫,繼承關係同樣,父類又稱爲基類

    python中類的繼承分爲:  單繼承和多繼承

class ParentClass1:
    pass

class ParentClass2:
    pass

class SubClass(ParentClass1): #單繼承
    pass

class SubClass(ParentClass1,ParentClass2): #多繼承
    pass

   子類繼承了基類的全部屬性

class Dad:
    money = 10
    def __init__(self,name):
        self.name = name
    def hit_son(self):
        print("打人")
class Son(Dad):#繼承參數「類」的全部屬性
    money = 5000#當子級類屬性跟父級類屬性重名時,調用當級類方法會先從當級尋找,找不到會去父級找
    pass
p1 = Son("eric")
print(p1.name)
p1.hit_son()
print(p1.money)

  當類之間有顯著的不一樣,  而且較小的類是較大的類所須要的組件時,  用組合比較好

  當類之間有不少相同的功能,  提取這些共同的功能作成基類,  用繼承比較好

繼承同時具備兩種含義

  含義一:繼承基類的方法,  而且作出本身的改變或者擴展  (代碼重用)

  含義二:聲明某個子類兼容於某基類, 定義一個接口類, 子類繼承接口類,  而且實現接口中定                     義的方法

接口繼承
import abc   #調用接口繼承模塊

class All_file(metaclass=abc.ABCMeta):#聲明某個子類兼容於某基類,定義一個接口類,子類繼承接口類,而且實現接口中定義的方法
    @abc.abstractclassmethod   #裝飾器使方法具有接口繼承特性
    def read(self):
        pass
    @abc.abstractclassmethod
    def write(self):
        pass

class Disk(All_file):#子類繼承基類時,必須對基類的方法進行派生纔可實例化
    def read(self):
        print("disk-read")
    def write(self):
        print("disk-write")
class Cd(All_file):
    def read(self):
        print("cd-read")
    def write(self):
        print("cd-write")
class Mem(All_file):
    def read(self):
        print("mem-read")
    def write(self):
        print("mem-write")
p1 = Disk()
p1.read()

繼承順序: python若是繼承了多個類, 遵循深度優先跟廣度優先順序

當類是經典類時,  多繼承狀況下,  會按照深度優先方式查找

當類是新式類時,  多繼承狀況下,  會按照廣度優先方式查找

經典類與新式類的差異:  新式類在定義時便自動繼承了object類,  而經典類沒有

新式類繼承順序: 對於你定義的每個類, python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的全部基類的線性順序列表

爲了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類爲止

而這個MRO列表的構造是經過一個C3線性化算法來實現的. 咱們不去深究這個算法的數學原理, 它實際上就是合併全部的MRO列表並遵循以下三條準則:

1.子類會先於父類被檢查

2.多個父類會根據它們在列表中的順序被檢查

3.若是對下一個類存在兩個合法的選擇,選擇第一個父類

 1 繼承順序
 2 
 3 
 4 class A:
 5     def test(self):
 6         print("testA")
 7 class B(A):
 8     def test(self):
 9         print("testB")
10 class C(A):
11     def test(self):
12         print("testC")
13 class D(B):
14     def test(self):
15         print("testD")
16 class E(C):
17     def test(self):
18         print("testE")
19 class F(D,E):
20     def test(self):
21         print("testF")
22 f1 = F()
23 print(F.__mro__)#(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
24 f1.test()#實例調用方法時,遵循mro順序,會優先從子級尋找,找不到往上,先廣度優先,若還找不到會找最深一級,若尚未會報錯

子類中調用父類方法

 1 class jiaotong:
 2     def __init__(self,name,speed):
 3         self.name = name
 4         self.speed = speed
 5     def run(self):
 6         print("%srunning!"%self.name)
 7 class bicycle(jiaotong):
 8     def __init__(self,name,speed,type):
 9         #jiaotong.__init__(self,name,speed)#第一種方法:類調用,子級繼承父級,能夠在調用父級方法的基礎上進行派生,減小重複代碼
10         super().__init__(name,speed)#第二種方法:用內置super().調用父級方法
11         self.type = type
12     def run(self):
13         jiaotong.run(self)
14         print("%s開動了"%self.name)
15 
16 
17 f1 = bicycle("danche",10,"meilida")
18 print(f1.name,f1.speed,f1.type)
19 f1.run()

多態,封裝

  多態:調用不一樣的子類將會產生不一樣的行爲,多態是在繼承上實現的

 1 class Dt:
 2     def __init__(self,name,temputer):
 3         self.name = name
 4         self.temputer = temputer
 5     def fu(self):
 6         if self.temputer < 0:
 7             print("【%s】溫度過低變成冰了!"%self.name)
 8         elif self.temputer > 0 and self.temputer < 100:
 9             print("【%s】變成水了!"%self.name)
10         elif self.temputer > 100:
11             print("【%s】溫度過高變成蒸汽了!"%self.name)
12 w1 = Dt("water",-2)
13 ice = Dt("ice",5)
14 steam = Dt("steam",150)
15 w1.fu()
16 ice.fu()
17 steam.fu()

  封裝的概念就是隱藏

  第一層面的封裝: 類就是麻袋, 這自己就是一種封裝

  第二個層面的封裝:類中定義私有的, 只在類的內部使用,外部沒法訪問, 類中定義屬性名時在其前面加上_或者__可實現該屬性的隱藏,但這種隱藏只是一種語言上的約定,python並不會從底層禁止你訪問

class People:
    _population = "60億"
    __star = "earth"
    def __init__(self,name,salary):
        self.name = name
        self.slary = salary
p1 = People("tom",1000)
print(p1._population)#對於第一種用_封裝的屬性,雖然是私有的,但仍然能夠訪問

print(p1._People__star)#對於第二種用__封裝的屬性,在其前面加上_類名仍然能夠訪問

  python並不會真的阻止你訪問私有屬性, 模塊也遵循這種預約, 若是模塊名以單下劃線開頭, 那         麼from module import *時不能導入,可是你from module import _private_module依然是能夠導         入的

  其實不少時候你去調用一個模塊的功能時會遇到單下劃線開頭的

  (socket._socket,sys._home,sys._clear_type_cache),這些都是私有的, 原則上是供內部調用的,

  但經過特殊方法依然能夠調用

  注意 : 雙下劃線開頭的屬性在繼承給子類時, 子類是沒法覆蓋的(原理也是基於python自動作了

  雙下劃線開頭的名字的重命名工做)

相關文章
相關標籤/搜索