python基礎(chǔ)-09-面向?qū)ο笾铩⒀b飾器

面向?qū)ο?/h1>
  • 類概念
  • 類的定義
  • 類的實例化
  • 類和實例的屬性
  • 類的私有變量
  • 數(shù)據(jù)封裝
  • 繼承
  • 多態(tài)
  • 多繼承
  • 類的特殊方法
  • 裝飾器
  • 類的裝飾器

1.面向?qū)ο?Object Oriented,OO)概念
    面向?qū)ο螅俏覀兙幊痰囊环N思維韭邓。
    早期的計算機編程是基于面向過程的方法,例如實現(xiàn)算術(shù)運算1+1+2 = 4虽缕,通過設(shè)計一個算法就可以解決當(dāng)時的問題始藕。隨著計算機技術(shù)的不斷提高,計算機被用于解決越來越復(fù)雜的問題氮趋。通過面向?qū)ο蟮姆绞轿榕桑瑢F(xiàn)實世界的事物抽象成對象,現(xiàn)實世界中的關(guān)系抽象成類剩胁、繼承诉植。通過面向?qū)ο蟮姆椒ǎ谟萌死斫獾姆绞疥枪郏瑢?fù)雜系統(tǒng)進(jìn)行分析晾腔、設(shè)計與編程。同時也提高了系統(tǒng)的可維護(hù)性啊犬,可擴展性灼擂,可重用性。
    (就是使編程的思維觉至,更接近與人的思維和認(rèn)知)


面向?qū)ο缶幊痰年P(guān)鍵剔应,就是類的定義。
類是對現(xiàn)實生活中一類具有共同特征的事物的抽象语御。
2.類的定義
基本形式:
    class ClassName(object):
        Statement
      
1.class定義類的關(guān)鍵字
2.ClassName類名峻贮,類名的每個單詞的首字母大寫(駝峰規(guī)則)。
3.object是父類名应闯,object是一切類的基類纤控。在python3中如果繼承類是基類可以省略不寫。
'''
class Animal(object):
    pass
'''

'''
重點:學(xué)會定義類孽锥,了解屬性和方法嚼黔,類的初始化和實例化。
定義類時惜辑,這種方法可以使類對象實例按某種特定的模式生產(chǎn)出來唬涧。
'''
#類方法:

后面的參數(shù)中第一個參數(shù)我們約定俗成的為self參數(shù)名,
self代表的是在類實例化后這個實例對象本身盛撑。

'''
class Animal: 
    #構(gòu)造方法碎节,實例化對象,必須調(diào)用__init__
    #在初始化的時候抵卫,默認(rèn)往構(gòu)造方法狮荔,傳入一個值
    #self是實例化對象本身
    def  __init__(self): 
        print("正在實例化一個對象")
    def test(self):#實例化對象調(diào)用方法胎撇,必須加上self
        print("aaa")
    def test1(self,b):#第一個參數(shù)默認(rèn)是self參數(shù),不需要傳值
        print("方法;test1,self=%s"%(type(self)))
    def test2():#未加self參數(shù)殖氏,只能通過  Animal.test2()直接調(diào)用晚树,實例化對象無法調(diào)用
        print("方法;test2")
運行結(jié)果:
>>> Animal().test1(1111)
正在實例化一個對象
方法;test1,self=<class '__main__.Animal'>
'''
'''
class Animal:   #當(dāng)我們沒有寫__init__(),默認(rèn)調(diào)用我們父類的__init__
    def test(self):
        print("aaa")
'''




初始化函數(shù)除了有self這個參數(shù)表示實例對象本身之外雅采,
其他的參數(shù)的定義也遵循函數(shù)的必備參數(shù)和默認(rèn)參數(shù)一樣的原則爵憎,
必備參數(shù)就是在實例化是一定要傳入的參數(shù),
默認(rèn)參數(shù)就是在定義時可以給這個參數(shù)一個初始值婚瓜。沒有函數(shù)名的函數(shù)

3.類的實例化
 基本形式:實例對象名 = 類名(參數(shù))

    在實例化的過程中宝鼓,self代表的就是這個實例對象自己。

    實例化時會把類名后面接的參數(shù)傳進(jìn)去賦值給實例巴刻,
    這樣傳進(jìn)去的參數(shù)就成為了這個實例對象的屬性愚铡。

    實例化的過程遵循函數(shù)調(diào)用的原則。
    在實例化時也必須個數(shù)和順序與定義時相同(使用關(guān)鍵字參數(shù)可以改變傳參的順序)胡陪。
    當(dāng)初始化函數(shù)定義時使用了默認(rèn)參數(shù)時沥寥,在實例化時默認(rèn)參數(shù)可以不傳參這時
    這個實例對象就會使用默認(rèn)的屬性,如果傳了參數(shù)進(jìn)去則會改變這參數(shù)值柠座,
    使實例化對象的屬性就為你傳進(jìn)來的這個參數(shù)营曼。

    isinstance(實例名,類名)
    判斷一個實例是不是這個類的實例愚隧。
4.類和實例的屬性

     類屬性
            .類屬性是可以直接通過“類名.屬性名”來訪問和修改蒂阱。
            .類屬性是這個類的所有實例對象所共有的屬性,
            任意一個實例對象都可以訪問并修改這個屬性(私有隱藏除外)狂塘。
            .對類屬性的修改录煤,遵循基本數(shù)據(jù)類型的特性:列表可以直接修改,字符串不可以荞胡,
            所以當(dāng)類屬性是一個列表時妈踊,通過任意一個實例對象對其進(jìn)行修改。
            但字符串類型的類屬性不能通過實例對象對其進(jìn)行修改泪漂。
            當(dāng)實例對不可變對象進(jìn)行修改之后廊营,會查找實例的類屬性,不會查找類的屬性萝勤,同時類的屬性不會邊
        
        實例屬性
            .在屬性前面加了self標(biāo)識的屬性為實例的屬性露筒。
            .在定義的時候用的self加屬性名字的形式,在查看實例的屬性時
            就是通過實例的名稱+‘.’+屬性名來訪問實例屬性敌卓。
'''
class Aniaml:
    eye=2  #共有的屬性
    def __init__(self,name,food):
        print("正在實例化")
        self.name=name #實例化屬性
        self.food=food
    def getName(self):
        print(self.name)
運行:
>>> dog=Aniaml("大黃","骨頭")
實例化屬性調(diào)用:
>>> dog.name  #調(diào)用實例屬性
'大黃'
類屬性調(diào)用:
>>>Aniaml.eye
>>> dog.eye 
      '''

        一些說明:
            .一般慎式,方法第一個參數(shù)被命名為self,,這僅僅是一個約定,
            self沒有特殊含義瘪吏,程序員遵循這個約定癣防。
            .查看類中的屬性和實例屬性可以調(diào)用__dict__方法返回屬性組成的字典。
            .Python中屬性的獲取是按照從下到上的順序來查找屬性
            .Python中的類和實例是兩個完全獨立的對象
            .Python中的屬性設(shè)置是針對對象本身進(jìn)行的
5.類的私有屬性和方法

        在Python中掌眠,通過單下劃線”_”來實現(xiàn)模塊級別的私有化蕾盯,
       一般約定以單下劃線”_”開頭的變量、函數(shù)為模塊私有的蓝丙,
       也就是說”from moduleName import *”將不會引入以單下劃線”_”開頭的變量刑枝、函數(shù)
       '''
       import random #顯示所有的方法,屬性
       from random import *  #只顯示
       '''

        對于Python中的類屬性迅腔,可以通過雙下劃線”__”來實現(xiàn)一定程度的私有化。
        _”和” __”的使用 更多的是一種規(guī)范/約定靠娱,并沒有真正達(dá)到限制的目的:

        “_”:以單下劃線開頭只能允許其本身與子類進(jìn)行訪問沧烈,(起到一個保護(hù)的作用)
        “__”:雙下劃線的表示的是私有類型的變量。這類屬性在運行時屬性名會加上單下劃線和類名像云。
        “__foo__”:以雙下劃線開頭和結(jié)尾的(__foo__)代表python里特殊方法專用的標(biāo)識锌雀,如 __init__()
        '''
       class Aniaml:
    eye=2
    _age=3
    __leg=4
    def __init__(self,name,food):
        self.name=name
        self.food=food
    def getName(self):
        print(self.name)
  >>> dog._age   #單_會隱藏屬性名稱
  >>> dog._Aniaml__leg  #雙_會隱藏屬性名稱,雙_會修改屬性的名稱
       '''

6.數(shù)據(jù)封裝

    在類里面數(shù)據(jù)屬性和行為函數(shù)的形式封裝起來迅诬,
    訪問時直接調(diào)用腋逆,不需知道類里面具體的實現(xiàn)方法。 比如侈贷,list.append
    封裝:
    def test2():
           print("方法;test2")
7.繼承
用法:
    .在定義類時惩歉,可以從已有的類繼承,
    被繼承的類稱為基類(父類)俏蛮,新定義的類稱為派生類(子類)撑蚌。
    
    .在類中找不到調(diào)用的屬性時就搜索基類,
     如果基類是從別的類派生而來搏屑,這個規(guī)則會遞歸的應(yīng)用上去争涌。
     反過來不行。
    
    .如果派生類中的屬性與基類屬性重名辣恋,那么派生類的屬性會覆蓋掉基類的屬性亮垫。
     包括初始化函數(shù)。
    
    .派生類在初始化函數(shù)中需要繼承和修改初始化過程伟骨,
     使用’類名+__init__(arg)’來實現(xiàn)繼承和私有特性,也可以使用super()函數(shù)饮潦。
    
    issubclass(類名1,類名2)
    判斷類1是否繼承了類2
    
作用:
    面向?qū)ο蟮木幊處淼闹饕锰幹皇谴a的重用携狭,實現(xiàn)這種重用的方法之一是通過繼承機制害晦。
    繼承完全可以理解成類之間的類型和子類型關(guān)系。
    
    子類在重寫父類方法之后,如果要繼承父類方法中的功能壹瘟,要先調(diào)用父類的方法  class.fun(self)
'''
class Aniaml:
    eye=2
    _age=3
    __leg=4
    def __init__(self,name,food):
        self.name=name
        self.food=food
    def getName(self):
        print(self.name)

class People(Aniaml):#繼承
    __leg=2
    def __init__(self,name,food,sex):
        self.name=name
        self.food=food
        self.sex=sex
    def getSex(self):
        print(self.sex)
'''

8.多態(tài)

當(dāng)派生類重寫了基類的方法時就實現(xiàn)了多態(tài)性鲫剿。(子類重寫父類方法)
class Aniaml:
    eye=2
    _age=3
    __leg=4
    def __init__(self,name,food):
        self.name=name
        self.food=food
    def getName(self):
        print(self.name)

class People(Aniaml):
    __leg=2
    def __init__(self,name,food,sex):
        self.name=name
        self.food=food
        self.sex=sex
    def getSex(self):
        print(self.sex)
    def speak(self):
        print("adsfsfd")

class Chinese(People):#中國人 
    def speak(self):#中國文說你好
        print("你好"

class America(People):#美國人
    def speak(self):#美國人說Hello
        print("Hello")
        
class Thai(People):#泰國人
    def speak(self):#泰國人說薩瓦迪卡
        print("薩瓦迪卡")

xiaomi=Chinese("小明","米飯","男")
jack=America("jack","面包","男")
lala=Thai("lala","香蕉","未知")
9.多繼承
#當(dāng)繼承的類有同種方法的時候,只會繼承前面一個的方法稻轨。調(diào)用父類方法super()
class Base:
    def play(self):
        print("This is base")

class A(Base):
    def play(self):
        print(type(self))
        print("This is a")
class B(Base):
    def play(self):
        print("This is b")
class C(A,B):
    def play(self):
        #A.play(self) #第一種調(diào)用父類的方法
        super().play()#第二種調(diào)用父類的方法灵莲,同super(C,self).play()
        #super(C,self).play()
        print("This is c")
運行效果:
<class '__main__.C'>
This is a
This is c
#對象的擴展使用
#C().__class__.mro()  查看對象的排序
#C(B,A)   C->B->A->Base->object 針對C繼承對象排序
#C(A,B)   C->A->B->Base->object 針對C繼承對象排序
class C(B,A):
    def play(self):
        #super(A,self).play()  #調(diào)用base
        super(B,self).play()  #調(diào)用a
>>> C().__class__.mro()  #C->B->A->Base->object 針對C繼承對象排序
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.Base'>, <class 'object'>]
10.類的特殊方法
千萬不要把自己往死胡同里面逼,否則你會走火入魔
'''
class Rectangle:
    '''測試'''
    aaa=1
    def __init__(self,length,width):
        if isinstance(length,(int,float)) and isinstance(width,(int,float)):
            self.length=length
            self.width=width
        else:
            print("請輸入int or float")
    def area(self):
        return self.length*self.width
    def __str__(self):
        return "這個長方形的面積%s"%self.area()
    def __repr__(self):
        return "長:%s 寬:%s"%(self.length,self.width)
    def __call__(self):
        print("這是一個Rectangle類殴俱,你要干嘛")
    def __add__(self,other):
        return self.area()+other.area()
    def __sub__(self,other):
        return self.area()-other.area()
r=Rectangle(2,3)
r1=Rectangle(2,3)
r2=Rectangle(2,3)

'''

#類屬性:
__dict__     # 類的屬性(包含一個字典政冻,由類的數(shù)據(jù)屬性組成)


>>> r.__dict__
{'length': 2, 'width': 3}
>>> r.aaa=33
>>> r.__dict__  
#注意,共有屬性线欲,當(dāng)不修改時明场,默認(rèn)引用Rectangle
#修改之后,才會出現(xiàn)再實例里面
{'length': 2, 'width': 3, 'aaa': 33}

__doc__     # 類的文檔字符串
>>> r.__doc__
'測試'

#類方法:(魔法方法) ,方法也是對象
    __init__    # 初始化
    __repr__    # 直接返回這個對象  repr() 函數(shù)就是調(diào)用對象的這個方法
    >>> r
    長:2 寬:3

    __str__     # print(obj) 如果類里面定義了__repr__李丰,沒有定義__str__ print(obj)也會返回__repr__的內(nèi)容苦锨,或者說__repr__的優(yōu)先級更高
    >>> print(r) #重寫print方法了
    這個長方形的面積6
    "%s"%"ssss"  對應(yīng)  __str__
    "%r"%"rrrr"  對應(yīng) __repr__
  
    __call__    # Obj() 使實例可被調(diào)用
    >>> r()
    這是一個Rectangle類,你要干嘛
    
#運算符方法
    __add__(self,other)     #x+y
    >>> r1+r2
    12

    __sub__(self,other)     #x-y 
    __mul__(self,other)     #x*y  
    __mod__(self,other)     #x%y
    __iadd__(self,other)    #x+=y
    __isub__(self,other)    #x-=y 
    __radd__(self,other)    #y+x
    __rsub__(self,other)    #y-x 
    __imul__(self,other)    #x*=y 
    __imod__(self,other)    #x%=y 
    
#和類有關(guān)的幾個函數(shù)  
    delattr()        # 刪除對象屬性
    getattr()        # 得到某個屬性值
    setattr()        # 給對象添加某個屬性值
    hasattr()          # 判斷對象object是否包含名為name的特性
    isinstance()      # 檢查對象是否是類的對象趴泌,返回True或False
    issubclass()      # 檢查一個類是否是另一個類的子類舟舒。返回True或False    
11.裝飾器
裝飾器(deco):
    裝飾函數(shù)的參數(shù)是被裝飾的函數(shù)對象,返回原函數(shù)對象裝飾器本質(zhì)上是一個Python函數(shù)嗜憔,它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能秃励,裝飾器的返回值也是一個函數(shù)對象
    概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能吉捶。

def  f1(func):
    print("f1 running")
    def f2(y):
        print("f2 running")
        return func(y)+1
    return f2
@f1
def  gun2(m):
    print("gun running")
    return m*m
#運行結(jié)果
f1 running
>>> gun2(5)
f2 running
gun running
26
運行流程
1.@f1->f1(gun2)->f2
2.f2夺鲜,等待調(diào)用
3.gun2(2)->當(dāng)參數(shù)5傳入->f2(5)
4.f2(5),開始運行->print("f2 running")->fun(y):func=gun2 y=5
5.gun2(5) 開始運行->print("gun running")->25
6.25+1=26

#測試時間的裝飾器
import time  #不要糾結(jié)

def run_time(func):
    def new_fun():
        t0 = time.time()
        print('star time: %s'%(time.strftime('%x',time.localtime())) )
        func()
        print('end time: %s'%(time.strftime('%x',time.localtime())) )
        print('run time: %s'%(time.time() - t0))
        
    return new_fun



@run_time
def test():
    for i in range(1,10):
        for j in range(1,i+1):
            print('%dx%d=%2s'%(j,i,i*j),end = ' ')
        print ()
12.類裝飾器
'''
class Rectangle:
    '''測試'''
    aaa=1
    def __init__(self,length,width):
        if isinstance(length,(int,float)) and isinstance(width,(int,float)):
            self.length=length
            self.width=width
        else:
            print("請輸入int or float")
    @property #可以把方法當(dāng)屬性使用
    def area(self):
        return self.length*self.width
    @staticmethod #把方法變成靜態(tài)方法
    def func():
        print("可以調(diào)用")
    @classmethod  #把實例化對象轉(zhuǎn)換成類
    def show(self):
        print(self)
        print("show fun")
  
>>> Rectangle(2,3).area
6
'''

@property 
    裝飾過的函數(shù)返回的不再是一個函數(shù)呐舔,而是一個property對象
    裝飾過后的方法不再是可調(diào)用的對象谣旁,可以看做數(shù)據(jù)屬性直接訪問。


@staticmethod #(靜態(tài)方法)
    把沒有參數(shù)的函數(shù)裝飾過后變成可被實例調(diào)用的函數(shù)滋早,      
    函數(shù)定義時是沒有參數(shù)的榄审,可以不接收參數(shù)

@classmethod (類方法)
    把裝飾過的方法變成一個classmethod類對象,既能能被類調(diào)用又能被實例調(diào)用杆麸。
    注意參數(shù)是cls代表這個類本身搁进。而是用實例的方法只能被實例調(diào)用。     
        
一般來說昔头,要使用某個類的方法饼问,需要先實例化一個對象再調(diào)用方法。
而使用@staticmethod或@classmethod揭斧,就可以不需要實例化莱革,直接類名.方法名()來調(diào)用峻堰。
這有利于組織代碼,把某些應(yīng)該屬于某個類的函數(shù)給放到那個類里去盅视,同時有利于命名空間的整潔
'''
#類裝飾器

'''
class Test_Class():
    def __init__(self,func):
        self.func=func
    def __call__(self):
        print("類")
        return self.func
@Test_Class
def fun_test():
    print("這只是一個測試")
運行:
>>> fun_test()
類
<function fun_test at 0x033081E0>
>>> fun_test()()
類
這只是一個測試
#python自帶的3個捐名,類的內(nèi)置裝飾器

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市闹击,隨后出現(xiàn)的幾起案子镶蹋,更是在濱河造成了極大的恐慌,老刑警劉巖赏半,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贺归,死亡現(xiàn)場離奇詭異,居然都是意外死亡断箫,警方通過查閱死者的電腦和手機拂酣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仲义,“玉大人婶熬,你說我怎么就攤上這事」獍樱” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵甥材,是天一觀的道長盯另。 經(jīng)常有香客問我,道長洲赵,這世上最難降的妖魔是什么鸳惯? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮叠萍,結(jié)果婚禮上芝发,老公的妹妹穿的比我還像新娘。我一直安慰自己苛谷,他們只是感情好辅鲸,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腹殿,像睡著了一般独悴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锣尉,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天刻炒,我揣著相機與錄音,去河邊找鬼自沧。 笑死坟奥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播爱谁,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼晒喷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了管行?” 一聲冷哼從身側(cè)響起厨埋,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捐顷,沒想到半個月后荡陷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡迅涮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年废赞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叮姑。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡唉地,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出传透,到底是詐尸還是另有隱情耘沼,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布朱盐,位于F島的核電站群嗤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏兵琳。R本人自食惡果不足惜狂秘,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望躯肌。 院中可真熱鬧者春,春花似錦、人聲如沸清女。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嫡丙。三九已至忠售,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迄沫,已是汗流浹背稻扬。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留羊瘩,地道東北人泰佳。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓盼砍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親逝她。 傳聞我的和親對象是個殘疾皇子浇坐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容