初識面向對象

1.面向對象的定義:3.7新特性html

2.面向對象的組合java

3.面向對象的三大特性python

 

面向過程 VS 面向對象 

面向過程的程序設計的核心是過程(流水線式思惟),過程即解決問題的步驟,面向過程的設計就比如精心設計好一條流水線,考慮周全何時處理什麼東西。

優勢是:極大的下降了寫程序的複雜度,只須要順着要執行的步驟,堆疊代碼便可。

缺點是:一套流水線或者流程就是用來解決一個問題,代碼牽一髮而動全身。

應用場景:一旦完成基本不多改變的場景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

 

面向對象的程序設計的核心是對象(上帝式思惟),要理解對象爲什麼物,必須把本身當成上帝,上帝眼裏世間存在的萬物皆爲對象,不存在的也能夠創造出來。面向對象的程序設計比如如來設計西遊記,如來要解決的問題是把經書傳給東土大唐,如來想了想解決這個問題須要四我的:唐僧,沙和尚,豬八戒,孫悟空,每一個人都有各自的特徵和技能(這就是對象的概念,特徵和技能分別對應對象的屬性和方法),然而這並很差玩,因而如來又安排了一羣妖魔鬼怪,爲了防止師徒四人在取經路上被搞死,又安排了一羣神仙保駕護航,這些都是對象。而後取經開始,師徒四人與妖魔鬼怪神仙互相纏鬥着直到最後取得真經。如來根本不會管師徒四人按照什麼流程去取。

面向對象的程序設計的

優勢是:解決了程序的擴展性。對某一個對象單獨修改,會馬上反映到整個體系中,如對遊戲中一我的物參數的特徵和技能修改都很容易。

缺點:可控性差,沒法向面向過程的程序設計流水線式的能夠很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題,即使是上帝也沒法預測最終結果。因而咱們常常看到一個遊戲人某一參數的修改極有可能致使陰霸的技能出現,一刀砍死3我的,這個遊戲就失去平衡。

應用場景:需求常常變化的軟件,通常需求的變化都集中在用戶層,互聯網應用,企業內部軟件,遊戲等都是面向對象的程序設計大顯身手的好地方。

在python 中面向對象的程序設計並非所有。

面向對象編程可使程序的維護和擴展變得更簡單,而且能夠大大提升程序開發效率 ,另外,基於面向對象的程序可使它人更加容易理解你的代碼邏輯,從而使團隊開發變得更從容。

瞭解一些名詞:類、對象、實例、實例化

類:具備相同特徵的一類事物(人、狗、老虎)

對象/實例:具體的某一個事物(隔壁阿花、樓下旺財)

實例化:類——>對象的過程(這在生活中表現的不明顯,咱們在後面再慢慢解釋)
面向過程VS面向對象

 

面向對象的定義git


類的定義,對象的實例化,類和對象的操做面試

class Person:                                                        #類名,類名都默認大寫開頭
    country = 'China'#創造了一個只要是這個類就必定有的屬性
                      #類屬性 靜態屬性
    def __init__(self,*args):                                        #初始化方法,self是對象,是必須傳參數
        #print(self.__dict__)
        self.name = args[0]
        self.hp = args[1]
        self.aggr = args[2]
        self.sex = args[3]
        #print(self.__dict__) 能夠把self當作一個字典,self後面的參數,是它的key,  類名()這裏括號裏的參數,傳進來後是它的value
        #print(id(self))
#注意,init的方法不能寫返回值
    def walk(self,n):                                                #此處叫作方法,self必須傳,且在第一個,後面還能夠傳其餘參數
        #注意此處self是默認寫法,且這個參數必須傳可是若是這裏寫成 s或者其餘名字也不要緊,由於當alex傳值進來的時候,其實就能夠取到值了,這裏只是個形參
        #因此其實此處walk和__init__實際上是兩個獨立函數,也能夠放在__init__上面,可是別這麼寫
        print('%s在散步,走了%s步'%(self.name,n))


#注意此處Person.name確定是取值不到的,類比你問你們,人類的名字是什麼,可是 能夠調用類屬性 Person.country
alex = Person('gousheng',100,1,'不詳')   #一旦開始初始化,就調用了object裏的 __new__方法,建立了self
# print(alex)
print(alex.__dict__)#查看全部的屬性
# print(alex.name)
# print(id(alex))  #alex和self內存地址id都是同樣的,因此能夠當作self就是alex
alex.walk(5) #等價於 Person.walk(alex),這是一種簡寫.alex做爲類的對象,能夠調用類的方法,並自動把自己屬性傳進去
#而後自己自動傳進去了,因此此時只須要再傳一個n給 walk方法

print(Person.__dict__['country']) #由於能夠用__dict__方法,因此能夠像操做字典同樣調用key value,可是類的字典不能改,對象才能改
#可是這樣改靜態屬性
Person.country = 'others'

print(alex.__dict__)               #同時能夠 alex.__dict__['name'] = 'gkx' 經過這樣來改屬性,可是通常不這麼用

print(alex.name)
alex.name = 'gkx'  #通常這麼修改   本質上是調用了__dict__方法
print(alex.name)

#對象 = 類名()
#過程:
    #類名() 首先 會創造出一個對象,建立了一個self變量
    #調用init方法,類名括號裏的參數會被這裏接收
    #執行init方法
    #返回self,也就返回給了alex對象自己
#對象能作的事:
    #查看屬性
    #調用方法
    #__dict__ 對於對象的增刪改查操做,均可以經過字典的語法進行
#類名能作的事:
    #實例化
    #調用靜態屬性(類屬性)
    #__dict__ 對於類中的dict方法,只能看不能操做
面向對象的定義
#通常來講你的值就是屬性,動做就是方法

class Person:
    def __init__(self,name,hp,aggr,sex):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex = sex

    def attack(self,dog):  #把狗的實例化傳進來
        dog.hp -= self.aggr
        print('%s被打了,掉了%s點血,剩下%s生命值'%(dog.name,self.aggr,dog.hp))

class Dog:
    def __init__(self,name,hp,aggr,kind):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.kind = kind

    def bite(self, person):
        person.hp -= self.aggr
        print('%s被咬了,掉了%s點血,剩下%s生命值'%(person.name,self.aggr,person.hp))

alex = Person('alex',200,2,'不詳')
jin = Dog('jinlaoban',600,50,'teddy')
alex.attack(jin)
jin.bite(alex)
# print(alex.__dict__)
練習1-人狗大戰
 #使用面向對象的狀況
#當有幾個函數,須要反反覆覆傳入相同參數的時候,就能夠考慮面向對象,這些參數都是對象的屬性
#很是明顯的處理一類事物 這些事物都有類似的屬性和功能
class Person:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def kanchai(self):
        print('%s,%s,%s,上山去砍柴'%(self.name,self.age,self.sex))

    def kaiche(self):
        print('%s,%s,%s,開車去東北'%(self.name,self.age,self.sex))

    def baojian(self):
        print('%s,%s,%s,去大保健'%(self.name,self.age,self.sex))

ming = Person('小明','10歲','')
wang = Person('老王','90歲','')
ming.kanchai()
wang.kaiche()


# import sys
# print(sys.path)
from math import pi
class Circle:

    def __init__(self,radi):
        self.radi = radi

    def permi(self):
        return pi*self.radi*2
        # print(2*pi*self.radi)

    def area(self):
        return pi*self.radi**2
        # print(pi*self.radi**2)

yuan = Circle(4)
print(yuan.permi())
print(yuan.area())
練習2-定義circle類,使用方法
class Foo:
    def func(self):    #當類中沒有 __init__ 也能夠實例化,可是就沒有辦法給實例傳屬性了
                        #不能初始化self,此處的self只是一個普通參數,接收的是一個 空的實例
        print('no init')

f1 = Foo()
f1.func()
能夠沒有__init__嗎
#類能夠定義兩種屬性  靜態屬性(類屬性) 和 動態屬性(方法)
#類能夠約束屬性

class Course:
    language = 'Chinese'
    def __init__(self,teacher,course_name,period,price):
        self.teacher = teacher
        self.name = course_name
        self.period = period
        self.price = price

print(Course.language)
python = Course('egon','python','6months',20000)
print(python.__dict__)



#對象中有指向類的指針,當對象尋找language的時候,先在自身的內存地址找,沒找到,再去類裏面找
#可是類不能找對象的,Course.name調用不到的
#類中的靜態變量,能夠被對象和類調用

#咱們知道
Course.language = 'English' #這樣子是能夠修改的
#可是
python.language = 'English' #也是能夠運行成功的,可是此時,對象是無權更改 Course裏的不可變數據類型的
#而後又在本身內部找不到 language去修改,因此 python這個對象在本身內部建立了 一個 language
print(python.__dict__) #此時裏面多了個language
#此時python這個對象,就再也接收不到 類裏的靜態屬性了,除非:
del python.language #刪除掉其內部的language才能夠從新接收

#因此:對於不可變數據類型來講(str,int),最好是用 類 去調用,儘可能不要從 對象 調用

              #~~~~~~~可變和不可變的靜態屬性的區別~~~~~~~~~
#可是對於 可變數據類型   好比 language = ['Chinese']   python.language[0]='English'是能夠改變 類 中對應的值的
#由於 對於列表來講,其內存地址確定不變,裏面是什麼元素都無所謂
#對於 可變數據類型 對象的修改是共享,從新賦值是獨立的


#小練習
class Foo:
    count = 0
    def __init__(self):
        Foo.count += 1

f1 = Foo()
print(Foo.count)
f2 = Foo()
print(Foo.count)
面向對象的命名空間
靜態屬性補充:
        因爲 self就能夠當作是類的對象自己。對於類到的靜態屬性,在類外能夠用 對象.static_name 來訪問。天然在類中也能夠 用 self.靜態名 來訪問了!
        >>> class A:
            x = 12
            def px(self):
                print("A中的x",self.x)
        
                
        >>> a = A()
        >>> a.px()
        A中的x 12
        >>> 
類中靜態屬性也能夠用self調用

#面向對象的命名空間:類和對象,分別調用什麼屬性。編程

#注意類的定義,若是__init__裏的參數都給了默認值,那麼在實例化的時候,能夠不帶參數。相似函數的形參方法及傳參順序設計模式

 

面向對象的組合微信


# 組合 :一個對象的屬性值是另一個類的對象
#        alex.weapon 是 Weapon類的對象
import time
class Person:
    def __init__(self,name,hp,aggr,sex):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex = sex
        self.money = 0

    def attack(self,dog):  #把狗的實例化傳進來
        dog.hp -= self.aggr
        print('%s被打了,掉了%s點血,剩下%s生命值'%(dog.name,self.aggr,dog.hp))

    def get_weapon(self,weapon):
        if self.money > weapon.price:
            self.money -= weapon.price
            self.weapon = weapon
            self.aggr += weapon.aggr


class Dog:
    def __init__(self,name,hp,aggr,kind):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.kind = kind

    def bite(self, person):
        person.hp -= self.aggr
        print('%s被咬了,掉了%s點血,剩下%s生命值'%(person.name,self.aggr,person.hp))

class Weapon:
    def __init__(self,name,aggr,njd,price):
        self.name = name
        self.aggr = aggr
        self.njd = njd
        self.price =price

    def beatdragon(self,person):
        if self.njd > 0:
            person.hp -= self.aggr*2
            print('%s被打了,掉了%s點血,剩下%s生命值' % (person.name, self.aggr*2, person.hp))
            self.njd -=1

alex = Person('alex',100,0.5,'不詳')
jin = Person('jinlaoban',500,100,'teddy')
w = Weapon('打狗棒',100,3,998)

alex.money += 1000
alex.attack(jin)
time.sleep(0.5)
alex.get_weapon(w)
time.sleep(0.5)
alex.attack(jin)
time.sleep(0.5)
alex.weapon.beatdragon(jin)
面向對象的組合
#組合
#1 能夠在初始化中 令   self.name = Lei(name,args1,args2..) 括號裏的值直接是具體的值
#2 能夠在初始化中 令   self.name = name  而後後續中  把一個其餘類的對象  傳入 name 中
#3 能夠在方法中,令  self.new = new  這個new爲方法中傳入的對象
#4 能夠在運行過程當中 令  self.xxx = 對象
#只要一發生,一個對象的屬性值是另外一個對象,則就是組合
#練習1
from cmath import pi
class Circle:
    def __init__(self,r):
        self.r = r

    def area(self):
        return pi*self.r**2

    def peri(self):
        return pi*self.r*2
# a = Circle(3)
# print(a.area())
# print(a.peri())

class Ring:
    def __init__(self,inside_r,outside_r):
        self.inside_r = Circle(inside_r)
        self.outside_r = Circle(outside_r)

    def area(self):
        return self.outside_r.area()-self.inside_r.area()

    def peri(self):
        return self.inside_r.peri()+self.outside_r.peri()

b = Ring(10,20)
print(b.area())
print(b.peri())

#練習2
class Course:
    def __init__(self,course_name,period,price):
        self.name = course_name
        self.period = period
        self.price = price

class Teacher:
    def __init__(self,name,course,sex,birh):
        self.name = name
        self.course = course
        self.sex = sex
        self.birh = birh
        self.course = Course('python', '6 month', 2000)


class Birth:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

bb = Birth(1981,9,22)
jing = Teacher('jing','python','femal',bb)
print(jing.birh.year)
組合練習

#什麼是組合,何時使用組合網絡

#一個類是能夠沒有 init 方法的,可是一旦沒有,就沒辦法初始化self
class Foo:
    def func(self):    #當類中沒有 __init__ 也能夠實例化,可是就沒有辦法給實例傳屬性了
                        #不能初始化self,此處的self只是一個普通參數,接收的是一個 空的實例
        print('no init')

f1 = Foo()
f1.func()

print(f1.func)
#<bound method Foo.func of <__main__.Foo object at 0x0000022110C02780>>
#到目前爲止,只有對象調用類的方法,才稱爲綁定方法  對象和類方法發生綁定關係


# 包 —— __init__
# import package —— 類的實例化的過程
# import time
# time.time()
綁定方法

 

面向對象的三大特性app

一.繼承

#python3中的類 叫作  新式類
#繼承是一種建立新類的方式,在python中,新建的類能夠繼承一個或多個父類,父類又可稱爲基類或超類,新建的類稱爲派生類或子類
#父類又稱 基類,超類    子類又稱 派生類
#一個父類能夠被屢次繼承,  在python中一個子類能夠繼承多個父類
#只有子類能找到父類,父類不知道本身有什麼子類

class A:pass
class B:pass
class A_son(A):pass
class B_son(A,B):pass
print(A_son.__bases__) #(<class '__main__.A'>,)
print(A.__bases__)  #(<class 'object'>,)   這個 object 是全部類的祖宗,沒有繼承父類的類,能夠看做其父類是 object
#在python3中全部的類都有父類,python3中的類又名 新式類
#也就說是說 class A:pass  寫成  class A(object):pass 也是徹底沒問題的。

#小例子
# class Animal:
#     def __init__(self,name,aggr,hp):
#         self.name = name
#         self.aggr = aggr
#         self.hp = hp
# class Dog(Animal):
#     pass
# class Person(Animal):
#     pass
#
# jin = Dog('金老闆',200,500)
# print(jin.name)

# 狗類 吃 喝 看門(guard)
# 鳥類 吃 喝 下蛋(lay)
class Animal:
    def __init__(self):
        print('執行Animal.__init__')
        self.func()
    def eat(self):
        print('%s eating'%self.name)
    def drink(self):
        print('%s drinking'%self.name)
    def func(self):
        print('Animal.func')

class Dog(Animal):    #當本身沒有init方法的時候,使用父類的 init
                      #此時Dog類建立了一個self,可是沒初始化值,因此回父類,init,而後接着 調用 self.func(),此時調用的是 Dog.fun(self)
                      #當本身有就調用本身的,沒有才會去找父類
    def guard(self):
        print('guarding')
    def func(self):
        print('Dog.func')
dog = Dog()

# class Bird(Animal):
#     def __init__(self,name):
#         self.name = name
#     def lay(self):
#         print('laying')
#
# b = Bird('jin')
# print(b.name)
初識繼承
#關於組合和繼承
#組合是 有,好比 老師類裏有生日類
#繼承是 是,子類是父類的關係,好比 dog是動物
#判斷是 有 仍是 是,來使用組合仍是繼承,還能夠判斷是否有重複代碼,有則是繼承

class Animal:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

    def eat(self):
        print('吃藥回血')
        self.hp+=100

class Dog(Animal):
    def __init__(self,name,hp,aggr,kind):
        Animal.__init__(self.name,aggr,hp)  #此處的self,傳的是 Dog類的self,這樣就能夠用Animal來把name,aggr,hp,初識給Dog類的self
        self.kind = kind              #此時即爲派生屬性

    def eat(self):
        Animal.eat(self)         #若子類方法和父類方法同名,既想實現父類的方法也想實現子類的方法,則須要在此調用父類的方法,傳入的self是 子類自己的
        self.teeth = 2
    def bite(self, person):         #派生方法
        person.hp -= self.aggr
        print('%s被咬了,掉了%s點血,剩下%s生命值'%(person.name,self.aggr,person.hp))



class Person(Animal):
    def __init__(self,name,hp,aggr,sex):
        Animal.__init__(self.name, aggr, hp)
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex = sex

    def attack(self,dog):  #把狗的實例化傳進來
        dog.hp -= self.aggr
        print('%s被打了,掉了%s點血,剩下%s生命值'%(dog.name,self.aggr,dog.hp))

# 父類中沒有的屬性 在子類中出現 叫作派生屬性
# 父類中沒有的方法 在子類中出現 叫作派生方法
# 只要是子類的對象調用,子類中有的名字 必定用子類的,子類中沒有才找父類的,若是父類也沒有報錯
# 若是父類 子類都有 用子類的
#可是若是非要用父類的方法,而本身子類已經用同名方法,則須要在子類的方法中調用 Animal.eat(self) 此處的self傳的是子類的self
初識繼承-派生
#super 是python3中才有的方法
class Animal:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp
    def eat(self):
        print('在animal中,回血了')

class Dog(Animal):
    def __init__(self,name,aggr,hp,kind):
        #Animal.__init__(self,name,aggr,hp) #注意此處參數順序,對於直接用父類進行init,參數順序和子類同樣便可
            # 對於用super進行init,子類參數順序必定要和父類同樣,會以父類的參數順序進行實例化,由於是父類在幫忙實例化Dog的self
        super().__init__(name,aggr,hp)  #super(Dog, self).__init__(name,aggr,hp) 括號中的 Dog類和self能夠省略
        self.kind = kind         #派生屬性順序只要按子類傳入順序便可

    def eat(self):
        #Animal.eat(self)   #若是子類中有同名的方法,子類會優先調用本身的方法,若是本身沒有,才返回去找父類要
        super().eat()       #兩種方式調取父類中的方法
        print('在Dog類中')

jin = Dog('金老闆',100,500,'teddy')
print(jin.__dict__)
jin.eat()  #此處若是
super(Dog,jin).eat()   #super在類外面調用,就要傳 dog類和對應的對象
super方法
#有道詞典0909筆記
# 新式類有個原則,就是全部點都要找到,若是保證這個點能找到,廣度優先(鑽石問題,小烏龜問題)
# python3中全部的類都是 新式類,都採用廣度優先,有個方法能夠查看繼承順序  print(B.mro())
# 在python2中的經典類,則時深度優先,一條路走到黑,走過的路不會走,而後換另外一條路
# python2中的新式類和經典類,能夠看下面的文章
# https://www.cnblogs.com/summer-cool/p/3884526.html
#平常工做中主要仍是使用單繼承,多繼承多用在設計模式中,及面試
# class F:
#     def func(self): print('F')
# class A(F):pass
#     # def func(self): print('A')
# class B(A):
#     pass
#     # def func(self): print('B')
# class E(F):pass
#     # def func(self): print('E')
# class C(E):
#     pass
#     # def func(self): print('C')
#
# class D(B,C):
#     pass
#     # def func(self):print('D')
#
# d = D()
# # d.func()
# print(D.mro())

# 新式類中的繼承順序 : 廣度優先


class A(object):   #著名的鑽石問題
    def func(self): print('A')

class B(A):
    def func(self):
        super().func()
        print('B')

class C(A):
    def func(self):
        super().func()
        print('C')

class D(B,C):
    def func(self):
        super().func()
        print('D')

b = D()
b.func()    #>>>  打印結果爲  A  C   B   D
print(B.mro())
#2.7
# 新式類 繼承object類的纔是新式類 廣度優先
# 經典類 若是你直接建立一個類在2.7中就是經典類 深度優先
# print(D.mro())
# D.mro()

# 單繼承 : 子類有的用子類 子類沒有用父類
# 多繼承中,咱們子類的對象調用一個方法,默認是就近原則,找的順序是什麼?
# 經典類中 深度優先
# 新式類中 廣度優先
# python2.7 新式類和經典類共存,新式類要繼承object
# python3   只有新式類,默認繼承object
# 經典類和新式類還有一個區別  mro方法只在新式類中存在
# super 只在python3中存在
# super的本質 :不是單純找父類 而是根據調用者的節點位置的廣度優先順序來的

# 繼續寫做業 :
# 學生管理系統  登陸,識別身份   進階 : 不一樣視圖不一樣的菜單
多繼承

#多繼承主要涉及到繼承順序,在新式類中是廣度優先,經典類中是深度優先,有個查看繼承順序的方法  claaaname.mro()

繼承特性中的兩大設計模式:接口類和抽象類。褒貶不一,重視程度不一

#接口類和抽象類都不能實例化
# java : 面向對象編程
# 設計模式   —— 接口
# 接口類 : python原生不支持,知足接口隔離原則
            #接口類支持多繼承
            #我要實現不一樣的功能,我就要去實現不一樣的接口,來繼承這些功能。同時我要規範不一樣的接口要有哪些方法。
            #規範的時候不實現這些方法,只在子類裏實現

# 抽象類 : python原生支持的

from abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):  # 元類 默認的元類 type
    @abstractmethod             #檢測子類的代碼是否有相同的方法
    def pay(self,money):pass   # 沒有實現這個方法

    @abstractmethod
    def func2(self):pass       #能夠在這個規範中定義不少方法,這些方法只提供方法名,可是徹底不用去實現。
                                #而後以這個方法做爲父類,當咱們寫類方法的時候,若是遺漏了某個方法,或拼寫錯誤,就會及時報錯
# 規範 :接口類或者抽象類均可以
# 接口類 支持多繼承,接口類中的全部的方法都必須不能實現 —— java
# 抽象類 不支持多繼承,抽象類中方法能夠有一些代碼的實現 —— java
class Wechat(Payment):
    def pay(self,money):
        print('已經用微信支付了%s元'%money)

class Alipay(Payment):
    def pay(self,money):
        print('已經用支付寶支付了%s元' % money)

class Applepay(Payment):
    def pay(self,money):  #當若是這裏的方法不叫pay,叫作fuqian,那麼最上面的規範,就會報錯,告訴你沒調用到pay方法
        print('已經用applepay支付了%s元' % money)

def pay(pay_obj,money):  # 統一支付入口
    pay_obj.pay(money)

# wechat = Wechat()
# ali = Alipay()
app = Applepay()
# wechat.pay(100)
# ali.pay(200)
p = Payment()
接口類
#規範
#這個例子是典形的 接口類 作的事情

#接口類
#我要實現不一樣的功能,我就要去實現不一樣的接口,來繼承這些功能。同時我要規範不一樣的接口要有哪些方法。
#規範的時候不實現這些方法,只在子類裏實現

# tiger 走路 游泳
# swan 走路 游泳 飛
# oldying 走路 飛
from abc import abstractmethod,ABCMeta
class Swim_Animal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self):pass

class Walk_Animal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):pass

class Fly_Animal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):pass

class Tiger(Walk_Animal,Swim_Animal):
    def walk(self):
        pass
    def swim(self):
        pass
class OldYing(Fly_Animal,Walk_Animal):pass
class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass

# 接口類  恰好知足接口隔離原則 面向對象開發的思想 規範
接口類的多繼承
#接口類 : python原生不支持,知足接口隔離原則
# 接口類 支持多繼承,接口類中的全部的方法都必須不能實現 —— java


# 抽象類 : python原生支持的
# 抽象類 不支持多繼承,抽象類中方法能夠有一些代碼的實現 —— java
#抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化
#若是說類是從一堆對象中抽取相同的內容而來的,那麼抽象類就是從一堆類中抽取相同的內容而來的,內容包括數據屬性和函數屬性。

#在接口類中,經過規範不一樣的接口,最後各個子類,去繼承這些接口類(多繼承),來達到實現功能的目的,接口類的規範,使得子類不會遺漏功能和拼寫錯誤
#在抽象類中,經過規範抽象出來的父類,當子類繼承的時候(單繼承),必須包含抽象類(父類)的功能,從而規範了子類
#抽象類中,子類方法必定要包含父類方法,只能多不能少

#一切皆文件
import abc #利用abc模塊實現抽象類

class All_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractmethod #定義抽象方法,無需實現功能
    def read(self):
        '子類必須定義讀功能'
        with open('filaname') as f:
            pass

    @abc.abstractmethod #定義抽象方法,無需實現功能
    def write(self):
        '子類必須定義寫功能'
        pass

class Txt(All_file): #子類繼承抽象類,可是必須定義read和write方法
    def read(self):
        print('文本數據的讀取方法')
    def write(self):
        print('文本數據的讀取方法')

class Sata(All_file): #子類繼承抽象類,可是必須定義read和write方法
    def read(self):
        print('硬盤數據的讀取方法')

    def write(self):
        print('硬盤數據的讀取方法')

class Process(All_file): #子類繼承抽象類,可是必須定義read和write方法
    def read(self):
        print('進程數據的讀取方法')

    def write(self):
        print('進程數據的讀取方法')

wenbenwenjian=Txt()

yingpanwenjian=Sata()

jinchengwenjian=Process()

#這樣你們都是被歸一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()

print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)

#爲何接口類中不能實現簡單功能
# 抽象類 : 規範
# 通常狀況下 單繼承 能實現的功能都是同樣的,因此在父類中能夠有一些簡單的基礎實現
# 多繼承的狀況 因爲功能比較複雜,因此不容易抽象出相同的功能的具體實現寫在父類中


# 抽象類仍是接口類 : 面向對象的開發規範 全部的接口類和抽象類都不能實例化
# java :
# java裏的全部類的繼承都是單繼承,因此抽象類完美的解決了單繼承需求中的規範問題
# 但對於多繼承的需求,因爲java自己語法的不支持,因此建立了接口Interface這個概念來解決多繼承的規範問題

# python
# python中沒有接口類  :
  #  python中自帶多繼承 因此咱們直接用class來實現了接口類
# python中支持抽象類  : 通常狀況下 單繼承  不能實例化
  #  且能夠實現python代碼
抽象類的單繼承
# java : 面向對象編程
# 設計模式   —— 接口
# 接口類 : python原生不支持,知足接口隔離原則,不能被實例化,接口類中的全部的方法都必須不能實現(java)
            #接口類支持多繼承
            #我要實現不一樣的功能,我就要去實現不一樣的接口,來繼承這些功能。同時我要規範不一樣的接口要有哪些方法。
            #規範的時候不實現這些方法,只在子類裏實現


# 抽象類 : python原生支持的
# 抽象類 不支持多繼承(或者說通常都是單繼承),抽象類中方法能夠有一些代碼的實現 —— java
#抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化
#若是說類是從一堆對象中抽取相同的內容而來的,那麼抽象類就是從一堆類中抽取相同的內容而來的,內容包括數據屬性和函數屬性。


         #功能歸納
#在接口類中,經過規範不一樣的接口,最後各個子類,去繼承這些接口類(多繼承),來達到實現功能的目的,接口類的規範,使得子類不會遺漏功能和拼寫錯誤
#在抽象類中,經過規範抽象出來的父類,當子類繼承的時候(單繼承),必須包含抽象類(父類)的功能,從而規範了子類
#抽象類中,子類方法必定要包含父類方法,只能多不能少
#接口類和抽象類都不能實例化
#接口類和抽象類,這兩種最主要的仍是規範了固定的功能,就是這些規範了的方法必定要實現。且具體的功能和子類本身自己的功能仍是要在子類中實現
#面試兩句話:這兩種都是規範,python中沒有接口類


            #爲何接口類中不能實現簡單功能
# 抽象類 : 規範
# 通常狀況下 單繼承 能實現的功能都是同樣的,因此在父類中能夠有一些簡單的基礎實現
# 多繼承的狀況 因爲功能比較複雜,因此不容易抽象出相同的功能的具體實現寫在父類中


# 多態 python 天生支持多態
# 接口類和抽象類 在python當中的應用點並非很是必要,不崇尚這兩類設計模式
#ptyhon中崇尚的是鴨子類型(模仿,一個跟一個),好比list和tuple,有好幾個類似方法,也沒有采用繼承來獲得


#在其餘靜態語言類型中java等,要給函數傳值,必需要先定義數據類型,因此在歸一化設計的時候,類做爲變量傳入的時候,須要提供一個父類,做爲數據類型定義,再傳入
#此時這個父類,空着也是空着,乾脆作一些規範(接口類和抽象類),一箭雙鵰



# java :
# java裏的全部類的繼承都是單繼承,因此抽象類完美的解決了單繼承需求中的規範問題
# 但對於多繼承的需求,因爲java自己語法的不支持,因此建立了接口Interface這個概念來解決多繼承的規範問題

# python:
# python中沒有接口類  :
  #  python中自帶多繼承 因此咱們直接用class來實現了接口類
# python中支持抽象類  : 通常狀況下 單繼承  不能實例化
  #  且能夠實現python代碼

#python中抽象類和接口類自己很類似,由於這種設計模式,是從java中學習過來的,有些公司推崇,有些沒有推崇
#python自己就支持多繼承,因此沒有接口類。
#因此受java影響,通常接口類用於多繼承,抽象類用於單繼承
抽象類和接口類總結

 

二.多態


python天生支持多態

# 多態 python 天生支持多態
# 接口類和抽象類 在python當中的應用點並非很是必要,不崇尚這兩類設計模式
#ptyhon中崇尚的是鴨子類型(模仿,一個跟一個),好比list和tuple,有好幾個類似方法,也沒有采用繼承來獲得


#在其餘靜態語言類型中java等,要給函數傳值,必需要先定義數據類型,因此在歸一化設計的時候,類做爲變量傳入的時候,須要提供一個父類,做爲數據類型定義,再傳入
#此時這個父類,空着也是空着,乾脆作一些規範(接口類和抽象類),一箭雙鵰


# def func(int num,str name):
#     pass
#
# func('alex',2)
# class Payment:pass

# class Alipay():
#     def pay(self,money):
#         print('已經用支付寶支付了%s元' % money)
#
# class Applepay():
#     def pay(self,money):
#         print('已經用applepay支付了%s元' % money)
#
# def pay(pay_obj,money):  # 統一支付入口  歸一化設計
#     pay_obj.pay(money)
#
# pay()

# 什麼是多態
# python 動態強類型的語言
# 鴨子類型
# list tuple
# 不崇尚根據繼承所得來的類似
# 我只是本身實現我本身的代碼就能夠了。
# 若是兩個類恰好類似,並不產生父類的子類的兄弟關係,而是鴨子類型
# list tuple 這種類似,是本身寫代碼的時候約束的,而不是經過父類約束的
# 優勢 : 鬆耦合 每一個類似的類之間都沒有影響
# 缺點 : 太隨意了,只能靠自覺

class List():
    def __len__(self):pass
class Tuple():
    def __len__(self):pass

def len(obj):
    return obj.__len__()

l = Tuple()
len(l)

# 強類型語言     多態
# python 語言    鴨子類型


# 接口類和抽象類 在python當中的應用點並非很是必要
多態和鴨子類型

 

三.封裝


重要知識點

#重要知識點
# 廣義上面向對象的封裝 :代碼的保護,面向對象的思想自己就是一種
# 只讓本身的對象能調用本身類中的方法

# 狹義上的封裝 —— 面向對象的三大特性之一
# 屬性 和 方法都藏起來 不讓你看見
class Person:
    __key = 123  # 私有靜態屬性
    def __init__(self,name,passwd):
        self.name = name
        self.__passwd = passwd   # 私有屬性

    def __get_pwd(self):         # 私有方法
        return self.__passwd   #只要在類的內部使用私有屬性,就會自動的帶上_類名

    def login(self):          # 正常的方法調用私有的方法
        return self.__get_pwd()

alex = Person('alex','alex3714')
print(alex.__dict__)    #設置私有變量,其實都是在變量名的基礎上加  _Person
print(Person.__dict__)
print(alex._Person__get_pwd())
# print(alex._Person__passwd)   # _類名__屬性名
# print(alex.login())

# 全部的私有 都是在變量的左邊加上雙下劃綫
    # 對象的私有屬性
    # 類中的私有方法
    # 類中的靜態私有屬性
# 全部的私有的 都不能在類的外部使用
初識封裝
#在C++語言中爲了保密,將全部的類屬性都設置爲私有
#父類中的私有屬性,不能被子類調用

#總結
#會用到私有屬性的場景
#1.隱藏起一個屬性,不想讓類的外部調用
#2.保護一個屬性,不想讓屬性隨意被改動
#3.保護一個屬性,不想讓子類調用
封裝總結
# 裝飾器:  @property     @func.setter(能夠傳惟一一個參數)   #func.deleter(與del配合使用)
# from math import pi
# print(pi)
#
# class Circle:
#     def __init__(self,r):
#         self.r = r        #爲何不把面積寫在屬性裏 self.area = pi*self.r**2。由於代碼屬性規範,面積不能直接改,只能用半徑改。
#
#     @property
#     def perimeter(self):
#         return pi*self.r*2
#
#     @property
#     def area(self):
#         return pi*self.r**2
#
# c = Circle(5)
# print(c.area)
# print(c.perimeter )

class Goods:
    discount = 0.5
    def __init__(self,name,price):
        self.__name = name
        self.price = price               #想調用私有屬性
    @property                           #加了property後可讓在類外調用函數,像調用屬性同樣,即免去加括號。可是此處就不能傳參了
    def name(self):
        return self.__name+'沒過時'
    @name.setter                       #在有 @property裝飾的name後,若是想修改私有屬性,能夠繼續調用裝飾器  函數名.setter
    def name(self,new_name):           #而後定義一個如出一轍的函數,參數爲傳入想改的值。
        self.__name = new_name

    @property
    def get_price(self):
        return self.price * Goods.discount


# apple = Goods('apple',5)
# print(apple.name)
# apple.name = '香蕉'
# print(apple.name)
# print(apple.get_price)

class Person:
    def __init__(self,name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.deleter       #這個deleter只有和調用的時候  del p.name 相做用纔會實現函數功能
    def name(self):
        del self.__name
p = Person('erge')
print(p.name)
del p.name         #這個del啥都沒作,只是執行了name方法,且deleter只有和調用的時候  del p.name 相做用纔會實現函數功能
print(p.name)      #我不能用對象去刪除一個方法,沒權力
封裝的應用-@property,.setter,.deleter
# staticmathod  靜態的方法 ***
# classmethod   類方法    ****
# 類的操做行爲
# class Goods:
#     __discount = 0.8
#     def __init__(self,name,price):
#         self.name = name
#         self.__price = price
#     @property
#     def price(self):
#         return self.__price * Goods.__discount
#     @classmethod   # 把一個方法 變成一個類中的方法,這個方法就直接能夠被類調用,不須要依託任何對象
#     def change_discount(cls,new_discount):  # 修改折扣
#         cls.__discount = new_discount
# apple = Goods('蘋果',5)
# print(apple.price)
# Goods.change_discount(0.5)   # Goods.change_discount(Goods)
# print(apple.price)
# 當這個方法的操做只涉及【靜態屬性】的時候 就應該使用classmethod來裝飾這個方法

# java
class Login:
    def __init__(self,name,password):
        self.name = name
        self.pwd = password
    def login(self):pass

    @staticmethod
    def get_usr_pwd():   # # 靜態方法 沒有默認的參數 就象函數同樣 ,固然也能夠傳參數
        usr = input('用戶名 :')
        pwd = input('密碼 :')
        Login(usr,pwd)

# Login.get_usr_pwd()
getattr(Login,'get_usr_pwd')()
# 在徹底面向對象的程序中,
# 若是一個函數 既和類沒有關係,也和對象沒有關係,就用staticmethod將它變爲一個靜態方法,隨時都能調用



# 類方法和靜態方法 都是類調用的
# 對象能夠調用類方法和靜態方法麼?   能夠   通常狀況下 推薦用類名調用
# 類方法 有一個默認參數 cls 表明這個類  cls
# 靜態方法 沒有默認的參數 就象函數同樣


# 面向對象的進階
# 網絡編程
classmethod和staticmethod

day59 Django 封裝mypage這個功能,從app01中的views的函數,封裝爲mypage做爲一個庫來使用 

 

補充:

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

    def walk(self):
        print("%s正在散步"%self.name)
        return self #須要返回self

    def eating(self):
        print("%s正在吃飯"%self.name)


f1 = Foo("gkx",22)
f1.walk().eating()  #在walk方法中return self,而後就能夠進行鏈式操做了
# f1.eating()
類的鏈式操做
class Foo:
    def func(self):    #當類中沒有 __init__ 也能夠實例化,可是就沒有辦法給實例傳屬性了
                        #不能初始化self,此處的self只是一個普通參數,接收的是一個 空的實例
        print('no init')

f1 = Foo()
f1.func()

#不把參數傳入self
class Person:
    def __init__(self,name,age):
        self.name = name     #self就是對象。能夠把self當作一個字典,self後面的參數,是它的key,  類名()這裏括號裏的參數,傳進來後是它的value
        age = age+1          #類的實例化默認是執行__init__函數,若是__init__的參數,不傳入self,那麼只能在__init__中使用,類中的方法調用不到
        print(age)           #換句話說,若是一個參數在__init__使用完後就沒用了,就能夠不用把它傳入 self

    def name_(self):
        print("你叫什麼",self.name)

p = Person("gkx",22)

#self.page_start = page_start  # 當page_start判斷完畢後,才傳入self。對於那些直接在__init__一開始就傳入self的來講,實例化的屬性就是傳入的值,不存在須要判斷的,因此能夠直接傳入
#self.page_end = page_end  # 可是此時page_start和page_end須要傳入參數後,再作必定的判斷才能肯定下來,肯定後才能傳給self,方便方法中調用
self理解!!必定要看
#同時傳入self的參數也不必定是要經過實例化傳入的,也能夠是通過實例化傳入的參數,經過實例化傳入的參數根據條件進行演變 而來的

 

 

 py3.7新特性

相關文章
相關標籤/搜索