欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python語(yǔ)言學(xué)習(xí)(五)(面向?qū)ο蠡A(chǔ)&進(jìn)階、整數(shù)比較和嵌套列表)

系統(tǒng) 1609 0

面向?qū)ο蠡A(chǔ)

  • 面向?qū)ο缶幊蹋喊岩唤M數(shù)據(jù)結(jié)構(gòu)和處理它們的方法組成對(duì)象(object),把相同行為的對(duì)象歸納為類(class),通過(guò)類的封裝(encapsulation)隱藏內(nèi)部細(xì)節(jié),通過(guò)繼承(inheritance)實(shí)現(xiàn)類的特化(specialization)和泛化(generalization),通過(guò)多態(tài)(polymorphism)實(shí)現(xiàn)基于對(duì)象類型的動(dòng)態(tài)分派。
  • 簡(jiǎn)單地說(shuō),類是對(duì)象的藍(lán)圖和模板,對(duì)象是類的實(shí)例。
  • python中可以使用class關(guān)鍵字定義類,在類中通過(guò)函數(shù)定義方法,代碼如下。
            
              class Student(object):

    # __init__是一個(gè)特殊方法用于在創(chuàng)建對(duì)象時(shí)進(jìn)行初始化操作
    # 通過(guò)這個(gè)方法我們可以為學(xué)生對(duì)象綁定name和age兩個(gè)屬性
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def study(self, course_name):
        print('%s正在學(xué)習(xí)%s.' % (self.name, course_name))

    # PEP 8要求標(biāo)識(shí)符的名字用全小寫(xiě)多個(gè)單詞用下劃線連接
    # 但是部分程序員和公司更傾向于使用駝峰命名法(駝峰標(biāo)識(shí))
    def watch_movie(self):
        if self.age < 18:
            print('%s只能觀看《熊出沒(méi)》.' % self.name)
        else:
            print('%s正在觀看島國(guó)愛(ài)情大電影.' % self.name)

            
          
  • 當(dāng)定義好類后,可以創(chuàng)建對(duì)象并給對(duì)象發(fā)消息。
            
              def main():
    # 創(chuàng)建學(xué)生對(duì)象并指定姓名和年齡
    stu1 = Student('駱昊', 38)
    # 給對(duì)象發(fā)study消息
    stu1.study('Python程序設(shè)計(jì)')
    # 給對(duì)象發(fā)watch_av消息
    stu1.watch_movie()
    stu2 = Student('王大錘', 15)
    stu2.study('思想品德')
    stu2.watch_movie()


if __name__ == '__main__':
    main()

            
          
  • 在python中,屬性和方法的訪問(wèn)權(quán)限只有兩種:公開(kāi)和私有。如果希望屬性是私有的,在給屬性命名時(shí)可以用兩個(gè)下劃線作為開(kāi)頭,代碼如下。
            
              class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    # AttributeError: 'Test' object has no attribute '__bar'
    test.__bar()
    # AttributeError: 'Test' object has no attribute '__foo'
    print(test.__foo)


if __name__ == "__main__":
    main()

            
          
  • 但事實(shí)上,python并未從語(yǔ)法上嚴(yán)格保證其私有性,而只是給私有的屬性和方法換了個(gè)名字妨礙訪問(wèn),如果了解更換名字的規(guī)則就可以訪問(wèn)到,代碼如下。
            
              class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    test._Test__bar()
    print(test._Test__foo)


if __name__ == "__main__":
    main()

            
          

面向?qū)ο筮M(jìn)階

  • 在實(shí)際開(kāi)發(fā)中,并不建議將屬性設(shè)為私有,這會(huì)導(dǎo)致子類無(wú)法訪問(wèn)。但如果直接將屬性暴露給外界也是有問(wèn)題的,建議是將屬性名以單下劃線開(kāi)頭,這樣既不會(huì)設(shè)為私有,又能夠表示其是受保護(hù)的,在訪問(wèn)該屬性時(shí)就要保持慎重。
    如果想訪問(wèn)該類屬性,可以通過(guò)屬性的getter(訪問(wèn)器)和setter(修改器)方法進(jìn)行相應(yīng)的操作。
    可以使用@property包裝器來(lái)包裝getter和setter方法,使得對(duì)屬性的訪問(wèn)既安全又方便。
            
              class Person(object):

    def __init__(self, name, age):
        self._name = name
        self._age = age

    # 訪問(wèn)器 - getter方法
    @property
    def name(self):
        return self._name

    # 訪問(wèn)器 - getter方法
    @property
    def age(self):
        return self._age

    # 修改器 - setter方法
    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        if self._age <= 16:
            print('%s正在玩飛行棋.' % self._name)
        else:
            print('%s正在玩斗地主.' % self._name)


def main():
    person = Person('王大錘', 12)
    person.play()
    person.age = 22
    person.play()
    # person.name = '白元芳'  # AttributeError: can't set attribute


if __name__ == '__main__':
    main()

            
          
  • python是一門動(dòng)態(tài)語(yǔ)言,允許在程序運(yùn)行時(shí)給對(duì)象綁定新的屬性或方法,也可對(duì)已綁定的進(jìn)行解綁。但如果需要限定自定義類型的對(duì)象只能綁定某些屬性,可以通過(guò)在類中定義_slots_變量來(lái)完成,_slots_的限定只對(duì)當(dāng)前類的對(duì)象生效,對(duì)子類不起作用。
            
              class Person(object):

    # 限定Person對(duì)象只能綁定_name, _age和_gender屬性
    __slots__ = ('_name', '_age', '_gender')

def main():
    person = Person('王大錘', 22)
    person._gender = '男'
    # AttributeError: 'Person' object has no attribute '_is_gay'
    # person._is_gay = True

            
          
  • 在類中定義的方法包括對(duì)象方法、靜態(tài)方法和類方法等。
  • 對(duì)象方法是發(fā)送給對(duì)象的消息,而靜態(tài)方法只要定義了類,不必建立類的實(shí)例就可使用,屬于類本身而非類的某個(gè)對(duì)象。
            
              from math import sqrt


class Triangle(object):

    def __init__(self, a, b, c):
        self._a = a
        self._b = b
        self._c = c

    @staticmethod # 靜態(tài)方法
    def is_valid(a, b, c):
        return a + b > c and b + c > a and a + c > b

    def perimeter(self):
        return self._a + self._b + self._c

    def area(self):
        half = self.perimeter() / 2
        return sqrt(half * (half - self._a) *
                    (half - self._b) * (half - self._c))


def main():
    a, b, c = 3, 4, 5
    # 靜態(tài)方法和類方法都是通過(guò)給類發(fā)消息來(lái)調(diào)用的
    if Triangle.is_valid(a, b, c):
        t = Triangle(a, b, c)
        print(t.perimeter())
        # 也可以通過(guò)給類發(fā)消息來(lái)調(diào)用對(duì)象方法但是要傳入接收消息的對(duì)象作為參數(shù)
        # print(Triangle.perimeter(t))
        print(t.area())
        # print(Triangle.area(t))
    else:
        print('無(wú)法構(gòu)成三角形.')


if __name__ == '__main__':
    main()

            
          
  • 類方法第一個(gè)參數(shù)約定名為cls,它代表當(dāng)前類相關(guān)信息的對(duì)象(類本身也是一個(gè)對(duì)象,也稱為類的元數(shù)據(jù)對(duì)象),通過(guò)該參數(shù)可以獲取和類相關(guān)的信息且創(chuàng)建類的對(duì)象。
            
              from time import time, localtime, sleep


class Clock(object):
    """數(shù)字時(shí)鐘"""

    def __init__(self, hour=0, minute=0, second=0):
        self._hour = hour
        self._minute = minute
        self._second = second

    @classmethod # 類方法
    def now(cls):
        ctime = localtime(time())
        return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)

    def run(self):
        """走字"""
        self._second += 1
        if self._second == 60:
            self._second = 0
            self._minute += 1
            if self._minute == 60:
                self._minute = 0
                self._hour += 1
                if self._hour == 24:
                    self._hour = 0

    def show(self):
        """顯示時(shí)間"""
        return '%02d:%02d:%02d' % \
               (self._hour, self._minute, self._second)


def main():
    # 通過(guò)類方法創(chuàng)建對(duì)象并獲取系統(tǒng)時(shí)間
    clock = Clock.now()
    while True:
        print(clock.show())
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

            
          
  • 類與類之間有三種關(guān)系:is-a、has-a和use-a。
    is-a關(guān)系即繼承或泛化,如學(xué)生-人。
    has-a關(guān)系即關(guān)聯(lián),如部門-員工。如果是整體和部分的關(guān)聯(lián),即聚合關(guān)系;如果整體進(jìn)一步負(fù)責(zé)了部分的生命周期(整體和部分是不可分割的,同時(shí)同在也同時(shí)消亡),即為合成關(guān)系,屬于最強(qiáng)的關(guān)聯(lián)關(guān)系。
    use-a關(guān)系即依賴,如司機(jī)的駕駛方法,其中參數(shù)用到了汽車。
  • 面向?qū)ο笕筇匦裕悍庋b、繼承和多態(tài)。
    封裝:隱藏一切可以隱藏的實(shí)現(xiàn)細(xì)節(jié),只向外界提供簡(jiǎn)單接口。在創(chuàng)建對(duì)象后,只需要調(diào)用方法就可以執(zhí)行,只需要知道方法的名字和傳入的參數(shù),而不需要知道方法內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)。
    繼承:讓一個(gè)類從另一個(gè)類那里將屬性和方法直接繼承下來(lái),減少重復(fù)代碼的編寫(xiě)。提供信息的為父類,又稱超類或基類;繼承信息的為子類,又稱派生或衍生類。子類不僅可以繼承父類的屬性和方法,還可以定義自己的,在實(shí)際開(kāi)發(fā)中,通常會(huì)用子類對(duì)象替換父類對(duì)象,即里氏替換原則。
    多態(tài):子類對(duì)父類的方法給出新的實(shí)現(xiàn)版本,稱為方法重寫(xiě)(override),從而讓父類的同一行為在子類中擁有不同版本。當(dāng)調(diào)用這個(gè)經(jīng)過(guò)子類重寫(xiě)的方法時(shí),不同子類對(duì)象會(huì)表現(xiàn)出不同的行為,即多態(tài)(poly-morphism)。
            
              from abc import ABCMeta, abstractmethod


class Pet(object, metaclass=ABCMeta):
    """寵物"""

    def __init__(self, nickname):
        self._nickname = nickname

    @abstractmethod
    def make_voice(self):
        """發(fā)出聲音"""
        pass


class Dog(Pet):
    """狗"""

    def make_voice(self):
        print('%s: 汪汪汪...' % self._nickname)


class Cat(Pet):
    """貓"""

    def make_voice(self):
        print('%s: 喵...喵...' % self._nickname)


def main():
    pets = [Dog('旺財(cái)'), Cat('凱蒂'), Dog('大黃')]
    for pet in pets:
        pet.make_voice()


if __name__ == '__main__':
    main()

            
          
  • 上面代碼里,將Pet類處理為抽象類,即不能夠創(chuàng)建對(duì)象,只為讓其他類來(lái)繼承。python從語(yǔ)法層面沒(méi)有提供對(duì)抽象類的支持,但可以通過(guò)abc模塊的ABCMeta元類和abstractmethod包裝器來(lái)達(dá)到抽象類的效果,如果一個(gè)類中存在抽象方法它就不能實(shí)例化。Dog和Cat子類分別對(duì)Pet類中的make_voice抽象方法進(jìn)行了不同地重寫(xiě),在main函數(shù)中調(diào)用該方法時(shí),就表現(xiàn)出了多態(tài)行為。

整數(shù)比較

  • 在python中比較兩個(gè)整數(shù)時(shí)有兩種運(yùn)算符:==和is:is比較的是兩者id值是否相等,即是否指向同一個(gè)地址;==比較兩者內(nèi)容是否相等,實(shí)際上調(diào)用了_eq_()方法。
  • 矛盾1 代碼如下。
            
              def main():
    x = y = -1
    while True:
        x += 1
        y += 1
        if x is y:
            print('%d is %d' % (x, y))
        else:
            print('Attention! %d is not %d' % (x, y))
            break

    x = y = 0
    while True:
        x -= 1
        y -= 1
        if x is y:
            print('%d is %d' % (x, y))
        else:
            print('Attention! %d is not %d' % (x, y))
            break


if __name__ == '__main__':
    main()

            
          
  • 矛盾1 解釋:python出于對(duì)性能的考慮,會(huì)將一些頻繁使用的整數(shù)對(duì)象緩存到一個(gè)叫small_ints的鏈表中,任何需要使用這些整數(shù)對(duì)象的時(shí)候,都不需要再重新創(chuàng)建,而是直接引用緩存。緩存的區(qū)間為[-5,256],當(dāng)使用is進(jìn)行比較時(shí),在該范圍內(nèi)的指向同一地址,而超出該范圍則為重新創(chuàng)建的,就會(huì)得到257 is 257結(jié)果為false的情況。
  • 矛盾2 代碼如下:
            
              import dis
a = 257


def main():
    b = 257  # 第6行
    c = 257  # 第7行
    print(b is c)  # True
    print(a is b)  # False
    print(a is c)  # False


if __name__ == "__main__":
    main()

            
          
  • 矛盾2 解釋:代碼塊是程序的最小執(zhí)行單位,在上述代碼中,a=257和main屬于兩個(gè)代碼塊。python為進(jìn)一步提高性能,規(guī)定在同一個(gè)代碼塊中創(chuàng)建的整數(shù)對(duì)象,即便超出[-5,256]的范圍,只要存在有值相同的整數(shù)對(duì)象,后續(xù)創(chuàng)建就直接引用。該規(guī)則對(duì)不在small_ints范圍內(nèi)的負(fù)數(shù)和負(fù)數(shù)值浮點(diǎn)數(shù)并不適用,但對(duì)非負(fù)浮點(diǎn)數(shù)和字符串都適用。因而c引用了b的257,而a與b不在同一個(gè)代碼塊內(nèi),才會(huì)得出注釋中的執(zhí)行結(jié)果。
  • 導(dǎo)入dis模塊并在main()方法下添加“dis.dis(main)”一句,可進(jìn)行反匯編,從字節(jié)碼的角度來(lái)看該代碼。運(yùn)行結(jié)果中,代碼第6、7行的257,是從同一位置加載的,而第9行的a則是從不同地方加載的,因此引用的是不同的對(duì)象。

嵌套列表

  • 把列表作為列表中的元素,即為嵌套列表,可以模擬現(xiàn)實(shí)中的表格、矩陣和棋盤(pán)等,但需謹(jǐn)慎使用,否則會(huì)出現(xiàn)問(wèn)題,代碼如下。
            
              def main():
    names = ['關(guān)羽', '張飛', '趙云', '馬超', '黃忠']
    subjs = ['語(yǔ)文', '數(shù)學(xué)', '英語(yǔ)']
    scores = [[0] * 3] * 5
    for row, name in enumerate(names):
        print('請(qǐng)輸入%s的成績(jī)' % name)
        for col, subj in enumerate(subjs):
            scores[row][col] = float(input(subj + ': '))
    print(scores)


if __name__ == '__main__':
    main()

            
          
  • 上述代碼原本打算錄入五位同學(xué)的三門成績(jī),但最終輸出結(jié)果卻發(fā)現(xiàn),每個(gè)學(xué)生三門課程的成績(jī)是一樣的,而且就是最后錄入的那個(gè)學(xué)生的成績(jī)。解決此問(wèn)題,需要區(qū)分開(kāi)對(duì)象和對(duì)象的引用兩個(gè)概念,這就涉及到內(nèi)存中的棧和堆。
  • 程序中可以使用的內(nèi)存從邏輯上可以分為五個(gè)部分,按照地址從高到低依次是:棧、堆、數(shù)據(jù)段、只讀數(shù)據(jù)段和代碼段。
    其中,棧用來(lái)存儲(chǔ)局部、臨時(shí)變量,以及函數(shù)調(diào)用時(shí)保存和恢復(fù)現(xiàn)場(chǎng)需要用到的數(shù)據(jù),這部分內(nèi)存在代碼塊執(zhí)行開(kāi)始時(shí)自動(dòng)分配,結(jié)束時(shí)自動(dòng)釋放,通常由編譯器自動(dòng)管理。
    堆的大小不固定,可以動(dòng)態(tài)地分配和回收,如果程序中有大量數(shù)據(jù)需要處理,通常都放在堆上。如果堆空間沒(méi)有被正確釋放,會(huì)引發(fā)內(nèi)存泄露的問(wèn)題,像Python、Java等都使用了垃圾回收機(jī)制(自動(dòng)回收不再使用的堆空間),來(lái)實(shí)現(xiàn)自動(dòng)化的內(nèi)存管理。
  • 因此以如下代碼為例,變量a并不是真正的對(duì)象,而是對(duì)象的引用,相當(dāng)于記錄了對(duì)象在堆空間中的地址;同理,變量b是列表容器的引用,它引用了堆空間上的列表容器,而列表容器中并沒(méi)有保存真正的對(duì)象。
            
              a = object()
b = ['apple', 'pitaya', 'grape']

            
          
  • 再看最初的程序,對(duì)列表進(jìn)行[[0]*3]*5操作時(shí),僅僅是將[0,0,0]這個(gè)列表的地址進(jìn)行了復(fù)制,并沒(méi)有創(chuàng)建新的列表對(duì)象。所以容器中雖然有五個(gè)元素,卻都引用的是同一個(gè)列表對(duì)象,每次輸入都相當(dāng)于對(duì)該列表對(duì)象進(jìn)行了修改,因此最終顯示的即為最后一個(gè)學(xué)生的成績(jī),正確的代碼如下。
            
              def main():
    names = ['關(guān)羽', '張飛', '趙云', '馬超', '黃忠']
    subjs = ['語(yǔ)文', '數(shù)學(xué)', '英語(yǔ)']
    scores = [[]] * 5 # 或scores = [[0] * 3 for _ in range(5)]
    for row, name in enumerate(names):
        print('請(qǐng)輸入%s的成績(jī)' % name)
        scores[row] = [0] * 3
        for col, subj in enumerate(subjs):
            scores[row][col] = float(input(subj + ': '))
    print(scores)


if __name__ == '__main__':
    main()

            
          

更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产精品成人一区二区三区 | 久久亚洲精品中文字幕二区 | 成人欧美日韩视频一区 | 国产精品视频观看 | 成人免费淫片aa视频免费 | 91成人精品 | 日本视频网址 | 国产精品美女久久久久久久久久久 | 国产成人免费 | 久久久久无码国产精品一区 | 亚洲欧美国产精品久久 | 婷婷人人爽人人做人人添 | 欧美簧片 | 天天拍天天干天天操 | 亚洲视频在线网 | 综合色播 | 欧美一级网站 | 999久久久精品视频在线观看 | 午夜影院在线免费观看视频 | 欧美一页| 深夜久久 | 亚洲香蕉久久一区二区三区四区 | 成人精品视频在线观看 | 欧美1区2区3区 | 久久国产成人福利播放 | 婷婷色综合 | 夜夜夜操操操 | 狠狠色噜噜狠狠狠狠2018 | 成人国产在线观看 | 香蕉国产人午夜视频在线 | 奇米影视首页 | 久久夜色精品 | 精品久久久网站 | 久爱视频www在线播放 | 欧美国产日韩在线观看 | 人人狠狠 | 欧美一级片毛片 | 久久毛片网站 | 五月激情综合婷婷 | 嫩草影院ncyy在线观看 | 亚洲成人av在线 |