1. 程式人生 > 實用技巧 ><筆記>第一篇:函式筆記

<筆記>第一篇:函式筆記

  • 為什麼要用函式?防止程式碼冗餘、可讀性差、可擴充套件性差(不易修改)
  • return:一旦遇到return ,結束整個函式,可以返回任何型別的值,返回多個值會成被組織成元祖被返回,也可以用多個值接收
  • 求最大值:max = x if x>y else y
  • 位置引數:位置引數必須傳值,不傳值就會報錯且必須在關鍵字引數前面,一個形參只能賦值一次
  • 預設引數:將變化比較小的值設定成預設引數
    • def stu_info(name,sex = "male"):
          """列印學生資訊函式,由於班中大部分學生都是男生,
              所以設定預設引數sex的預設值為'male'
          """
          print(name,sex)
      
      
      stu_info('alex')
      stu_info('eva','female')  
  • 引數陷阱:預設引數設定成一個可變資料型別  
    • def defult_param(a, l=[]):
          l.append(a)
          print(l)
      
      
      defult_param('A')  # ['A']
      defult_param('B')  # ['A', 'B']
      defult_param('C')  # ['A', 'B', 'C']
  • 動態引數:
    • 把按照位置傳值多餘的引數都由*args統一接收,儲存成一個元祖形式
    • 把按照關鍵字傳值多餘的引數都由**kwargs統一接收,儲存成一個元祖形式
  • 標準寫法
    • 標準模式
      def 函式名(引數1,引數2,*args,預設引數,**kwargs):
              """註釋:函式功能和引數說明"""
              函式體
              ……
              return 返回值
  • 直譯器遇到函式:當遇到函式定義的時候直譯器只是象徵性的將函式名讀入記憶體,表示知道這個函式的存在了,至於函式內部的變數和邏輯直譯器根本不關心。 
  • 名稱空間(三種):
    • 全域性名稱空間:類似於全域性變數
    • 區域性名稱空間:函式內的名稱空間,類似區域性變數  
    • 內建名稱空間:存放了python直譯器為我們提供的名字:input,print,str,list,tuple...它們都是我們熟悉的,拿過來就可以用的方法。  
    • 載入順序
      • 內建名稱空間(程式執行前載入)->全域性名稱空間(程式執行中:從上到下載入)->區域性名稱空間(程式執行中:呼叫時才載入)
    • 在區域性呼叫:區域性名稱空間->全域性名稱空間->內建名稱空間

    • 在全域性呼叫:全域性名稱空間->內建名稱空間
  • 函式名的本質:函式的記憶體地址,可以當函式的引數和返回值  
  • 閉包函式:內部函式包含對外部作用域而非全域性作用域名字的引用,該內部函式稱為閉包函式
  • 裝飾器函式:在不修改原函式及其呼叫方式的情況下對原函式進行擴充套件
    • 版本1.0---沒有實現返回值和引數
      • import time
        
        def func1():
            print('in func1')
        
        def timer(func):
            def inner():
                start = time.time()
                func()
                print(time.time() - start)
            return inner
        
        func1 = timer(func1)
        func1()
    • 版本2.0--沒有實現引數
      • import time
        def timer(func):
            def inner():
                start = time.time()
                func()
                print(time.time() - start)
            return inner
        
        @timer   #==> func1 = timer(func1)
        def func1():
            print('in func1')
        
        
        func1()
    • 版本3.0---裝飾器也被稱為'語法糖'

      • import time
        def timer(func):
            def inner(*args,**kwargs):
                start = time.time()
                re = func(*args,**kwargs)
                print(time.time() - start)
                return re
            return inner
        
        @timer   #==> func2 = timer(func2)
        def func2(a):
            print('in func2 and get a:%s'%(a))
            return 'fun2 over'
        
        func2('aaaaaa')
        print(func2('aaaaaa'))
    • 固定格式

      • def timer(func):
            def inner(*args,**kwargs):
                '''執行函式之前要做的'''
                re = func(*args,**kwargs)
                '''執行函式之後要做的'''
                return re
            return inner
    • 裝飾器完美符合開放封閉原則:擴充套件開放,修改封閉

    • 擴充套件版本:版本4.0多個裝飾器裝飾同一個函式

      • def wrapper1(func):
            def inner():
                print('wrapper1 ,before func')
                func()
                print('wrapper1 ,after func')
            return inner
        
        def wrapper2(func):
            def inner():
                print('wrapper2 ,before func')
                func()
                print('wrapper2 ,after func')
            return inner
        
        @wrapper2
        @wrapper1
        def f():
            print('in f')
        
        f()
  • 思考:索引取值和for取值的區別?

  • 字串、列表、元組、字典、集合都可以被for迴圈,說明他們都是可迭代的。

  • 什麼是可迭代?可以將某個資料集內的資料"一個挨著一個的取出來",就叫迭代.從結果上來看能被for迴圈的就叫可迭代的

  • 更底層,可迭代需要滿足什麼?可以被迭代需要滿足可迭代協議(內部實現了__iter__方法)

  • 可以被迭代的物件,後面跟__iter__方法就叫迭代器  

    • print([1,2].__iter__())
      # <list_iterator object at 0x00000000024FA048>
  • 列表迭代器跟列表相比多了哪些方法?

    • print(set(dir([1, 2].__iter__())) - set(dir([1, 2])))
      #  {'__setstate__', '__length_hint__', '__next__'} 
    • __setstate__:根據索引值確定從哪裡開始迭代          
    • __length_hint__:計算長度
    • __next__:一個一個取值(取下一個值)
  • for迴圈之所以能一個一個取值,是因為反覆實現__next__方法 
  • for迴圈的本質:for迴圈就是基於迭代器協議提供了一個統一的可以遍歷所有物件的方法,即在遍歷之前,先呼叫物件的__iter__方法將其轉換成一個迭代器,然後使用迭代器協議去實現迴圈訪問,這樣所有的物件就都可以通過for迴圈來遍歷了,而且你看到的效果也確實如此,這就是無所不能的for迴圈.
  • 生成器:我們自己寫的這個能實現迭代器功能的東西就叫生成器。(我們自己寫實現迭代器功能的函式就叫生成器)  
  • Python中提供的生成器
    • 生成器函式:常規函式定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函式的狀態,以便下次重它離開的地方繼續執行 
    • 生成器表示式:類似於列表推導,但是,生成器返回按需產生結果的一個物件,而不是一次構建一個結果列表
      • egg_list=['雞蛋%s' %i for i in range(10)] #列表解析
        laomuji=('雞蛋%s' %i for i in range(10))#生成器表示式
        # 把列表解析的[]換成()得到的就是生成器表示式
    • 生成器是惰性執行,需要才執行,呼叫一次執行一次,這樣就不會再記憶體中生成太多資料

    • 優點

      • 延遲計算:一次返回一個結果。也就是說,它不會一次生成所有的結果,這對於大資料量處理,將會非常有用。 

        • #列表解析
          sum([i for i in range(100000000)])#記憶體佔用大,機器容易卡死
           
          #生成器表示式
          sum(i for i in range(100000000))#幾乎不佔記憶體
      • 提高程式碼可讀性 

  • 匿名函式:函式名 = lambda 引數 :返回值

  • 常用內建函式

    • str型別程式碼執行:eval,exec

    • 數字:bool,int,float,abs,divmod,min,max,sum,round,pow

    • 序列——列表和元組相關的:list和tuple

    • 序列——字串相關的:str,bytes,repr

    • 序列:reversed,slice

    • 資料集合——字典和集合:dict,set,frozenset

    • 資料集合:len,sorted,enumerate,zip,filter,map

    • 其他:input,print,type,hash,open,import,dir

  • 遞迴:在一個函式裡再呼叫這個函式本身,這種魔性的使用函式的方式就叫做遞迴。

    • 遞迴的最大深度——997

    • 修改最大遞迴深度

      • import sys
        print(sys.setrecursionlimit(100000))