天天看點

python基礎程式設計day15

day14回顧

異常
    語句處理的語句
      try-except 語句
          捕獲錯誤通知,把程式的異常狀态改回正常狀态
      try-finally 語句
          執行在正常流程和異常流程下都必須要執行的語句
      raise 語句
          抛出(觸發) 錯誤通知,讓程式進入到異常流程
      assert 語句(斷言語句)
          根據條件,決定是否抛出AssertionError類型的錯誤
      
  疊代器
    iter(obj)    用obj這個可疊代對象傳回obj的疊代器
    next(疊代器)  向疊代器要資料,當沒有資料時會收到 
                 StopIteration異常通知
    s = "hello"
    it = iter(s)
    print(next(it))  # h
    print(next(it))  # e      

新的一天

什麼是生成器:

生成器是能夠動态提供資料的可疊代對象
  生成器是在程式運作時生成資料,與容器類不同,它通常不會在記憶體中
    儲存大量的資料,而是現用現生成

  生成器有兩種:
       生成器函數
     生成器表達式


生成器函數:
  含有yield 語句的函數是生成器函數,此函數被調用将傳回一個生成
    器對象
  yield 翻譯為(産生或生成)      

yield 語句

文法:
    yield 表達式
  說明:
    yield 隻能用于def 函數中,目的是将此函數作為生成器函數使用
    yield 用來生成資料,供疊代器的next(it) 函數使用 
  示例見:
 ```
  def myyield():
      print("即将生成2")
      yield 2
      print("即将生成3")
      yield 3
  
      print('生成器函數調用結束')
  
  g = myyield()  # g綁定的是一個生成器,生成器是可疊代對象
  print("g綁定的是:", g)  # g=<generator object ...at >
  
  it = iter(g)  # it 綁定g的疊代器
  v = next(it)
  print('v=', v)  # v=2
  v2 = next(it)
  print('v2=', v2)  # v2=3
  v3 = next(it)  # 觸發StopIteration異常
  print('v3=', v3)   

```

  說明:
    生成器函數的調用将傳回一個生成器對象,生成器對象是一個可疊
       代對象
    生成器函數調用return會觸發一個StopIteration異常(即生成
       資料結束)
  示例2見:
   ```
  def myinteger(n):
      i = 0
      while i < n:
          yield i
          i += 1
  
  L = []
  for x in myinteger(30000000000000000):
      # print(x)  # 列印 0, 1, 2
      L.append(x)```

  練習:
    寫一個生成器函數 myeven(start, stop) 用來生成從start開始
    到stop結束(不包含stop)區間内的一系列偶數
    如:
      def myeven(start, stop):
          for i in range(start,stop):
          if i%2==0:
            yeild i
          
  
      events = list(myeven(10, 20))
      print(events)  #  [10, 12, 14, 16, 18]
      for x in myeven(21, 30):
          print(x)  # 列印: 22 24 26 28
      L = [x**2 for x in myeven(1, 10)]
      print(L)  # [4, 16, 36, 64]      

生成器表達式:

文法:
    ( 表達式 for 變量 in 可疊代對象 [if 真值表達式] )
  說明:
    if 子句部分可以省略
  作用:
    用推導式形式建立一個新的生成器
  示例:
    gen = (x**2 for x in range(1, 5))
    it = iter(gen)
    next(it)  # 1
    next(it)  # 4
    next(it)  # 9
    next(it)  # 16
    next(it)  # StopIteration



練習:
  1. 已知有清單:
    L = [2, 3, 5, 7]
    1) 寫一個生成器函數,讓此函數能夠動态的提供資料,資料為原
       清單的數字的平方加1
  def func(L):
    for i in L:
      yeild i**2+1
    2) 寫一個生成器表達式,讓此表達式能夠動态提供資料,資料為原
       清單的數字的平方加1
  L = (X**2+1 for x in L)
    3) 生成一個清單,此清單的資料為原清單的數字的平方加1

說明:
  生成器函數或生成器表達式調用後傳回的生成器,
    即是生成器也是疊代器
  示例:
    gen = (x**2 for x in range(3))
    it = iter(gen)  # 向生成器擷取疊代器,但傳回的是gen
    next(it)  # 0
    next(gen) # 1
    next(it) # 4
    next(gen) # StopIteration      
示例:
    numbers = [10086, 10000, 10010, 95588]
    names = ['中國移動', '中國電信', '中國聯通']
    for t in zip(numbers, names):
        print(t)  # (10086, '中國移動'), (10000, '中國電信')

    d = dict(zip(numbers, names))
    print(d)  # {10086: '中國移動', 10000:'中國電信', ...}
    
    for t in zip(names, numbers, range(1, 1000)):
        print(t)  # ('中國移動', 10086, 1), (...)

    用生成器函數實作myzip函數來代替zip函數,示例見:
    ```
    # 此示例示意自己定義生成器函數myzip來替代zip函數
    # def myzip(*args):
    def myzip(iter1, iter2):
        it1 = iter(iter1)  # 拿到iter1的疊代器
        it2 = iter(iter2)  # 拿到iter2的疊代器
        while True:
            try:
                x = next(it1)  # 取出元組的第一個元素
                y = next(it2)  # 取出第二個元素
                yield (x, y)
            except StopIteration:
                return
    
    
    # def myzip(iter1, iter2):
    #     it1 = iter(iter1)  # 拿到iter1的疊代器
    #     it2 = iter(iter2)  # 拿到iter2的疊代器
    #     while True:
    #         x = next(it1)  # 取出元組的第一個元素
    #         y = next(it2)  # 取出第二個元素
    #         yield (x, y)
    
    numbers = [10086, 10000, 10010, 95588]
    names = ['中國移動', '中國電信', '中國聯通']
    for t in myzip(numbers, names):
        print(t)  # (10086, '中國移動'), (10000, '中國電信')
    ```      

enumerate 函數

-  函數格式:
      enumerate(iterable, start=0)
    作用:
      生成一個枚舉可疊代對象,此可疊代對象生成類型為(索引,值)的
      元組,,預設索引從0開始,也可以用start指定
    示例:
      names = ['中國移動', '中國電信', '中國聯通']
      for t in enumerate(names):
          print(t)  # (0, '中國移動'), (1, '中國電信), (...)
  
    
  練習:
    自己寫一個與enumerate功能相同的生成器函數myenumerate
    如:
      def myenumerate(...):
          ...
      
      names = ['中國移動', '中國電信', '中國聯通']
      for t in myenumerate(names):
          print(t)  # (0, '中國移動'), (1, '中國電信), (...)
  
      for t in myenumerate(names, 100):
          print(t)  # (100, '中國移動'), (101, '中國電信), (...)      

序列:

字元串str, 清單list, 元組tuple, 位元組串bytes,
    位元組數組bytearray
  
  
  位元組串bytes(也叫做位元組序列)
    作用:
      存儲以位元組為機關的資料,
    說明:
      位元組串是不可以改變的序列
      位元組是0~255之間的整數,用來表示一個位元組的取值
  
  位元組:
    位元組(byte)是以8個位(bit)為機關的存儲單元
     0b11111111  --> 255
     0b00000000  --> 0


  建立空位元組串的字面值:
    b''
    b""
    b''''''
    b""""""
  建立非空位元組串字面值
    b'ABCD'
    b"ABCD"
    b'\x41\x42\x43\x44'
  
  位元組串的構造函數:
    bytes()              生成一個空的位元組串,等同于b''
    bytes(整型可疊代對象)   用可疊代對象初始化一個字元串
    bytes(整數n)          生成n個值為0的位元組串
    bytes(字元串, encode='utf-8')  用字元串的轉換編碼
                          生成一個位元組串

    示例:
      B = bytes()    # B = b''
      B = bytes(range(65, 80))  # B = b'ABCDEF...'
      B = bytes(10)             # B = b'\x00\x00\x00...'
      B = bytes('tarena', 'utf-8')  # B=b'tarena'

  位元組串的運算
    +   +=    *     *=  
    <   <=   >   >=   ==   != 
    in  , not in 
    索引index 和 切片
    注:  位元組串為不可變類型,隻能索引和切片取值,不能指派
  
    示例:
      b = b'ABC' + b'123'  # b = b'ABC123'
      b = b'ABC' * 3    # b=b'ABCABCABC'
      b'ABC' > b'AB'   # True
      65 in b'ABC'      # True
      b = b'ABCDEFG'
      print(b[0])   # 65
      print(b[::2])  # b'ACEG'      

内建函數:

len(x), max(x), min(x), sum(x), any(x), all(x)      

bytes 和 str 的差別:

bytes 存儲位元組(0~255的整數)
    str 存儲unicode字元(0~0x10FFFF的整數)
  
  str 與 bytes 的轉換
         編碼(encode)
    str -----------> bytes
        b = s.encode(encoding='utf-8')
  
         解碼(decode)
    bytes -----------> str
        s = b.decode(encoding='utf-8')
  
    示例:
      s = "hello中國"
      b = s.encode()  # 等同于 s.encode('utf-8')
      # b = b'hello\xe4\xb8\xad\xe5\x9b\xbd'
      s2 = b.decode()  # s2 = 'hello中國'      

位元組數組 bytearray

可變的位元組序列

建立位元組數組的構造函數 bytearray
  bytearray()  建立空的位元組數組
  bytearray(整數n)  建立n個值為0的位元組數組
  bytearray(整型可疊代對象)  用可疊代對象初始化一個位元組數組
  bytearray(字元串,encoding='utf-8')  用字元串的轉換編碼
               生成一個位元組數組
運算符:
  +  +=   *   *=
  < <= > >= == !=
  in, not in
  索引和切片:
    注: 位元組數組支援索引和切片指派,規則同清單的索引和切片
        指派規則      

位元組數組的方法見:

文檔參見:
    方法      說明
  B.clear() 清空
  B.append(n) 追加一個位元組(n為0-255的整數)
  B.remove(value) 删除第一個出現的位元組,如果沒有出現,則産生ValueError錯誤
  B.reverse() 位元組的順序進行反轉
  B.decode(encoding='utf-8')  
  B.find(sub[, start[, end]]) 

  練習:
    寫一個程式,從鍵盤輸入一段字元串,用變量s綁定
    s = input()
    b = s.encode("utf-8")
    print(len(s))
    print(len(b))
    s2 = b.decode("utf-8")
    print(s==s2)
    1. 将此字元串轉為位元組串用變量b綁定,并列印出來
    2. 列印出字元串s的長度和位元組串b的長度
    3. 将b位元組串再轉換為字元串用變量s2綁定,再判斷s2與s是否相同
  
  練習:
    1. 看下列函數的輸出結果是什麼? 為什麼?
      第一個程式:
        L = [2, 3, 5, 7]
        A = [x * 10 for x in L]
        it = iter(A)
        print(next(it))  # ????
        L[1] = 333
        print(next(it))  # ????
      第二個程式:
        L = [2, 3, 5, 7]
        A = (x * 10 for x in L)
        it = iter(A)
        print(next(it))  # 20
        L[1] = 333
        print(next(it))  # 30
  
    2. 試寫一個myfilter函數,要求此函數與内建的filter函數的功能
       一緻
      如:
        
          def myfilter(fn, iterable):
            for x in iterable:
                if fn(x):
                    yield x

      for x in myfilter(lambda x: x%2==1, range(10)):
          print(x)  # 1 3 5 7 9

    3. 寫一個生成器函數myxrange([start, ] stop[, step]) 來
       生成一系列整數,
         要求:
            myxrange功能與range功能完全相同
            不允許調用range函數和清單
            ```
            def myxrange(start, stop=None, step=None):
              if stop is None:
                  stop = start
                  start = 0
              if step is None:
                  step = 1
          
              # 正向
              if step > 0:
                  while start < stop:
                      yield start
                      start += step
              # 反向
              else:
                  while start > stop:
                      yield start
                      start += step  # 加上負的步長
          
          for x in myxrange(3):
              print(x)
          
          for x in myxrange(100, 103):
              print(x)
          
          for x in myxrange(1000, 1010, 3):
              print(x)
          
          for x in myxrange(10, 0, -3):
              print(x)
          ```
    4. 預習:
        檔案 和 面向對象程式設計
    
    5. 分解質因數,輸入一個正整數,分析質因數
      如
      ```
  def get_zhiyinshu(x):
      '''如x=90
      傳回: [2, 3, 3, 5]
      '''
   L = []
   while x > 1:  # 它一定至少有一個質因數
          for i in range(2, x + 1):
              if x % i == 0:  # i為x的質因數
                  L.append(i)
                  # 修改正x的下一次的值
                  x = int(x / i)
                  break  # 終止本次打開
      return L
  n = int(input("請輸入一個整數: "))
  L = get_zhiyinshu(n)
  L2 = [str(x) for x in L]
  s = str(n) + '=' + '*'.join(L2)
  print(s)
    ```
        輸入: 90
      列印:
        90 = 2*3*3*5
        (質因數是的指最小能被原數整除的系數(不包括1))