Python3學(xué)習(xí)筆記(二)

好久沒更新了呀,Python的學(xué)習(xí)可不能落下!??

面向?qū)ο缶幊?/h2>

面向?qū)ο笤O(shè)計(jì)思想:抽象出類(Class),根據(jù)類創(chuàng)建實(shí)例(Instance)。
面向?qū)ο蟮娜筇攸c(diǎn):封裝,繼承,多態(tài)。

  1. 類和實(shí)例:

    • 類的定義:class Student(object): pass Student類繼承了object
    • 創(chuàng)建實(shí)例:yzl = Student() , 創(chuàng)建實(shí)例后,可以自由的給實(shí)例綁定屬性yzl.age = 18, 僅對(duì)本實(shí)例有效
    • 類的方法定義:def __init__(self, name, age):, 第一個(gè)變量必須是self, 但不用傳,表示此實(shí)例變量。
  2. 訪問限制:以__開頭的是私有變量,外部訪問不到(但其實(shí)可以訪問到,只是Python解釋器把私有變量換了個(gè)名字,比如_Student__name,以_開頭的雖然可以訪問,但也要當(dāng)做私有變量,不要輕易訪問??傊?,Python本身沒有任何機(jī)制阻止你干壞事,一切全靠自覺。

    class Student(object):
    
    def __init__(self, name, score):
        self.__name = name
        self.__score = score
    
    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))
    
  3. 繼承與多態(tài):對(duì)于靜態(tài)語言,比如Java,一個(gè)函數(shù)的入?yún)㈩愋捅仨毷谴_定的,而對(duì)于動(dòng)態(tài)語言,只要file-like object即可. 鴨子類型:一個(gè)對(duì)象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子。
    只要whatever有run()方法就可以。

    def run_twice(whatever):
            whatever.run()
    
  4. 獲取對(duì)象信息:

    • type() 判斷對(duì)象類型 type(123): <class 'int'>
    • isinstance() 判斷一個(gè)對(duì)象是否是某種類型 isinstance('abc', str): True
    • dir() 獲取一個(gè)對(duì)象的所有屬性和方法,它返回一個(gè)包含字符串的list
    • hasattr(obj, 'x') 獲取屬性 setattr(obj, 'y', 19) 設(shè)置屬性,注意:只有在不知道對(duì)象信息的時(shí)候,我們才會(huì)去獲取對(duì)象信息
  5. 實(shí)例屬性和類屬性:不通過__init__()構(gòu)造,直接在class里定義屬性的是類屬性。實(shí)例屬性和類屬性名字不要一樣,否則類屬性在當(dāng)前實(shí)例會(huì)被覆蓋掉。

  6. 限制實(shí)例的屬性:__slots__ = ('name', 'age') , 定義一個(gè)__slots__ 限制類的實(shí)例屬性只能在tuple里,否則將報(bào)AttributeError錯(cuò)誤,注意:__slots__只作用于當(dāng)前類實(shí)例,對(duì)子類不起作用,若子類也定義了slots,則還要加上父類的slots。

  7. @property : 相當(dāng)于 getter,@name.setter : 相當(dāng)于 setter,這兩個(gè)decorator的目的是讓方法變?yōu)閷傩?調(diào)用方法生成了屬性),可以寫出更簡短的代碼,同時(shí)保證對(duì)參數(shù)進(jìn)行必要性的檢查。

    class Screen(object):
        @property
        def width(self):
            return self.__width
    
        @width.setter
        def width(self, w):
            self.__width = w
    
    s = Screen()
    print(dir(s))  # 結(jié)果為: ['__class__', '__delattr__', '__dict__', ...]
    s.width = 1
    print(dir(s))  # 結(jié)果為: ['_Screen__width', '__class__', '__delattr__', '__dict__', ...]
    
  8. 多繼承:Python支持多繼承,class class Dog(Mammal, Runnable):

  9. 定制類:重寫class的函數(shù),使之符合我們的需求,以下是常用的定制類:

    • __str__ : 自定義打印實(shí)例,變量調(diào)用的是__repr__

      class Student(object):
          def __init__(self, name):
              self.name = name
          def __str__(self):
              return 'Student object (name=%s)' % self.name
          __repr__ = __str__
      
    • __iter__: 返回一個(gè)迭代對(duì)象,通過__next()__方法循環(huán)獲取下一個(gè)值,知道遇到StopIteration錯(cuò)誤時(shí)推出循環(huán)

      class Fib(object):
         def __init__(self):
             self.a, self.b = 0, 1 # 初始化兩個(gè)計(jì)數(shù)器a,b
      
         def __iter__(self):
             return self # 實(shí)例本身就是迭代對(duì)象,故返回自己
      
         def __next__(self):
             self.a, self.b = self.b, self.a + self.b # 計(jì)算下一個(gè)值
             if self.a > 100000: # 退出循環(huán)的條件
                 raise StopIteration();
             return self.a # 返回下一個(gè)值
      
    • __getitem__: 按照下標(biāo)或切片取出元素

      # 重寫__getitem__ 支持索引和切片
      class Fib(object):
          def __getitem__(self, n):
              if isinstance(n, int):  # n是索引
                  a, b = 1, 1
                  for x in range(n):
                      a, b = b, a + b
                  return a
              if isinstance(n, slice):  # n是切片
                  start = n.start
                  stop = n.stop
                  if start is None:
                      start = 0
                  a, b = 1, 1
                  L = []
                  for x in range(stop):
                      if x >= start:
                          L.append(a)
                      a, b = b, a + b
                  return L
      
      print(Fib()[9])
      print(Fib()[:10])
      
    • __getattr__: 動(dòng)態(tài)返回一個(gè)屬性, 可以寫一個(gè)鏈?zhǔn)秸{(diào)用

      def __getattr__(self, path):
         return Chain('%s/%s' % (self._path, path))
      
    • __call__: 直接在實(shí)例本身上調(diào)用, 通過callable()函數(shù),可以判斷一個(gè)對(duì)象是否是“可調(diào)用”對(duì)象。

      class Student(object):
          def __init__(self, name):
              self.name = name
      
          def __call__(self):
              print('My name is %s.' % self.name)
      
      s = Student('DreamYoung')
      if callable(s):
          s()  # self參數(shù)不要傳入    
      
  10. 枚舉類:Enum 枚舉類,把一組相關(guān)常量定義在一個(gè)class中,class不可變,成員可直接比較

    from enum import Enum, unique
    
    @unique  # @unique裝飾器用于檢查有沒有重復(fù)值
    class Weekday(Enum):
        Sun = 0  # Sun的value被設(shè)定為0
        Mon = 1, 2
        Tue = 2
    
    print(Weekday.Sun)          # Weekday.Sun
    print(Weekday.Sun.value)    # 0
    print(Weekday.Mon.value)    # (1, 2)
    print(Weekday(2))           # Weekday.Tue
    print(Weekday['Tue'])       # Weekday.Tue
    print(Weekday['Tue'].value) # 2
    

    可見,既可以用成員名稱引用枚舉常量,又可以直接根據(jù)value的值獲得枚舉常量

  11. 元類:Python的class的定義是運(yùn)行時(shí)創(chuàng)建的,創(chuàng)建的方法就是使用type()函數(shù)!type()函數(shù)既可以返回一個(gè)對(duì)象的類型,又可以創(chuàng)建出新的類型,無需使用class關(guān)鍵字。

    def fun(self, name='DreamYoung'):
        print('Hello, ' + name)
        
    Hello = type('Hello', (object,), dict(hello=fun))  # 創(chuàng)建Hello class
    
    h = Hello()
    h.hello()
    

    type()函數(shù)需要三個(gè)參數(shù):函數(shù)名稱,繼承的父類集合(tuple),方法名綁定的函數(shù)。
    Python創(chuàng)建類也是掃一下class關(guān)鍵字,然后通過type創(chuàng)建出來類。
    如果要控制類的行為,可以使用元類?metaclass,可以把類理解為metaclass創(chuàng)建的實(shí)例。 先定義metaclass,就可以創(chuàng)建類,最后創(chuàng)建實(shí)例。metaclass暫時(shí)不會(huì)用到,如果需要深入了解,可以參考這篇文章

錯(cuò)誤、調(diào)試和測(cè)試

  1. 錯(cuò)誤:Python內(nèi)置了try...except...finally...用于捕獲異常,所有的異常都繼承自BaseException, 查看異常繼承關(guān)系

    注意:

    • except可以有多個(gè),多個(gè)except異常 父類會(huì)覆蓋子類的異常, except后可以跟else
    • finally在最后執(zhí)行,可以不寫
    • 可以使用logging模塊記錄日志,通過查看調(diào)用堆棧,定位排查錯(cuò)誤

    寫法:

    try:
        print(1/0)
    except ZeroDivisionError as e:
        logging.exception(e)
    else:
        print('else')
    finally:
        print('finally')
    
  2. 調(diào)試:要想調(diào)試起來爽,要善于使用logging!

    logging有debug、info、warning、error幾個(gè)級(jí)別,通過:

    import logging
    logging.basicConfig(level=logging.INFO) # info級(jí)別日志,debug日志不會(huì)顯示
    

    指定當(dāng)前模塊的日志級(jí)別,logging的好處是通過簡單的配置,日志可以輸出到文件等等

  3. 單元測(cè)試:編寫單元測(cè)試需要引入unittest模塊,并編寫一個(gè)從unittest.TestCase繼承測(cè)試類。
    注意,測(cè)試方法必須以test開頭(test_xxx()),否則在測(cè)試時(shí)不會(huì)被執(zhí)行。unittest提供了很多內(nèi)置條件的判斷,比如:assertEqual()assertRaises()等等 用于判斷輸出值是否是我們的期望值。

    運(yùn)行前與運(yùn)行后:編寫兩個(gè)特殊的方法setUp()tearDown(),在每個(gè)單元測(cè)試方法執(zhí)行之前執(zhí)行setUp(),執(zhí)行之后執(zhí)行tearDown()。這個(gè)用處大大的,比如可以在setUp()方法連接測(cè)試庫,tearDown()方法關(guān)閉連接。

    運(yùn)行單元測(cè)試有兩種方法:

    1. 加上兩行代碼,這樣可以當(dāng)做正常的Python腳步運(yùn)行:

      if __name__ == '__main__':
          unittest.main()
      
    2. (薦)通過命令行參數(shù)直接運(yùn)行單元測(cè)試 :可以批量執(zhí)行單元測(cè)試

      $ python3 -m unittest my_test1.py my_test2.py
      
  4. 文檔測(cè)試:Python的很多官方文檔都是示例代碼,通過doctest模塊,可以提前并執(zhí)行文檔注釋代碼。
    比如就絕對(duì)值的函數(shù)abs()寫上這樣的注釋:

    def abs(n):
        """
        Function to get absolute value of number.
    
        Example:
    
        >>> abs('')
        Traceback (most recent call last):
            ...
        TypeError: unorderable types: str() >= int()
        >>> abs(1)
        1
        >>> abs(-1)
        1
        >>> abs(0)
        0
        """
        return n if n >= 0 else (-n + 1)  # 正確的代碼應(yīng)為: return n if n >= 0 else (-n)
    
    if __name__ == '__main__':
        import doctest
    
        doctest.testmod()
    

    會(huì)得到以下輸出:


File "xxxx/demo/dream/young/python/Test.py", line 13, in main.abs
Failed example:
abs(-1)
Expected:
1
Got:
2


1 items had failures:
1 of 4 in main.abs
Test Failed 1 failures.


如果沒有輸出任何信息,說明注釋代碼沒有錯(cuò)誤。注意:當(dāng)模塊正常導(dǎo)入時(shí),doctest不會(huì)被執(zhí)行。只有在命令行直接運(yùn)行時(shí),才執(zhí)行doctest。所以,不必?fù)?dān)心doctest會(huì)在非測(cè)試環(huán)境下執(zhí)行。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容