1. 程式人生 > >python 函數進階

python 函數進階

內部函數 調用 code post 聲明變量 logs username 會計 變現

函數進階


命名空間

  • namespace, 顧名思義, 就是存放名字的地方.舉例:若聲明變量 x = 1, 值1存放與內存中, 那變量名x 就存放在命名空間裏. 命名空間是存放x 和 1 綁定關系的地方.

  • 名稱空間共3種,分別如下:
  • locals: 當前所在的函數內的名稱空間,包括局部變量和形參
  • globals: 全局變量,函數定義所在模塊最外層的名字空間
  • builtins: 內置模塊的名字空間

  • 作用域範圍
  • 全局範圍:全局存活,全局有效
  • 局部範圍:臨時存活,局部有效

  • LEGB 代表名字查找順序: locals -> enclosing function -> globals -> builtins
    • locals 是函數內的名字空間,包括局部變量和形參
    • enclosing 外部嵌套函數的名字空間
    • globals 全局變量,函數定義所在模塊的名字空間
    • builtins 內置模塊的名字空間

閉包

  • 初步理解: 函數定義和函數表達式位於另外一個函數體內(嵌套函數),外部函數返回的是內部函數的函數名,而且內部 函數可以直接訪問他們所在的外部函數中聲明的所有局部變量、參數, 當這樣的一個內部函數在包含他們的外部函數之外被調用的時候,就會形成閉包。

  • 定義: 返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,除了函數內部定義的局部變量,其次就是使用自己外層包裹的作用域,

def outer():
    name = ‘jack‘
    def inner():
        print("在inner裏打印外層函數的變量", name)

    return inner

f = outer()   # outer函數執行後等價於 f == inner
f()  # inner()

裝飾器

  • 作用: 在不改變現有函數的代碼的情況下,進一步增強函數的功能
  • 前提條件: 能形成閉包, 函數作為參數傳入上級函數的命名空間,供內部函數返回掉調用
使用裝飾器版本
  • 簡單實例:
def f1(func):
    def inner():
        return
func(n) return inner @f1 def f2(x): print(x) f2()

過程詳細解析
  1. 給函數f2加上裝飾器f2可以理解為f = f1(f2)這個過程,此時先執行等式右邊內容,f2函數作為參數被傳入外部函數的命名空間,存儲起來;
  2. f1返回inner, 等價於f = inner;
  3. 這就形成了閉包,在inner函數外部函數f1的外部調用f()這個函數,就同時於調用了內部函數inner()
  4. 此時inner結果返回之前傳入的參數函數(),即f2()
  5. 此時inner函數就會向外部函數的命名空間查詢變量或參數,找到之前傳入的f2函數參數
  6. 由於之前傳入的函數名就是外部函數f2(),所以直接會調用外部函數f2()
  7. 最後,函數名修改後並不會影響函數內部代碼執行,所以直接將f 改為 f2, 那麽就是實現了裝飾器功能, 在不改變f2代碼的同時,在啟動前會運行f1(),此時生成中間函數明變量,函數名如果是f2的話,那麽在後續調用f2()的時候同時也就啟動了函數f2()。

實例2:給代碼加認證函數

USERNAME = ‘lynnfang‘
PASSWORD = ‘abc‘
lock_status = 0
login_status = 0

def login(func, *args):
    def inner(*args, **kwargs):
        global lock_status, login_status
        
        if lock_status == 1:
            print(‘您的賬戶已被鎖定!‘)
            
        else:
            if login_status == 0:
                n = 0
                while n < 3:
                    username = input(‘>>> 用戶名: ‘)
                    password = input(">>> 密碼: ")
                    if username == USERNAME and password == PASSWORD:
                        n = 3
                        login_status = 1
                        return func()
                    else:
                            n += 1
                else:
                    lock_status = 1

            else:
                return func()
                
    return inner

@login
def china():
    print(‘----中國專區----‘)

@login
def japan():
    print(‘----日本專區----‘)

china()
japan()

代碼解析
  1. 在不改變已寫好china()和japan()函數代碼的前提下,對其加用戶認證,只有認證通過才能調用函數內部表達式
  2. 首先將執行代碼腳本,python檢測到 @ 符號,將會將對應的函數名稱作為參數傳入login()函數的命名空間
  3. f1 = inner, f2 = inner
  4. 由於無形的中間函數可以賦值為之前傳入的函數名,所以當調用這個函數名時候等同於外部調用inner
  5. 進入inner函數後,聲明全局變量後,就可以在嵌套函數內部修改全局變量值,同時,在嵌套函數內部也會將全局變量值作為邏輯語句的判斷條件,但最後肯定會返回之前傳入的函數調用()
  6. 進入login()函數的命名空間查找對應的函數參數,由於函數參數就是之前傳入的外部函數,所以也就調用了外部函數,順利進入外部執行函數內部
  7. 只要不退出程序,下一次進入login函數就會參考之前的全局變量來判斷執行了,所以只要一次登錄,以後就不需要重復登錄了

生成器(generator)

  • 特點: 生成器不會把結果保存在一個系列中,而是保持生成器的狀態,在每次進行叠代時返回一個值,直到遇到StopIteration異常結束。

  • 生成器表達式: 通列表解析語法,只不過把列表解析的[ ]換成( )

  • 與列表解析的差異:生成器表達式能做的事情列表解析基本都能處理,只不過在需要處理的序列比較大時,列表解析比較費內存。

  • 典型生成器 g = (i for i in range(1000),g就是生成器,next(g)就可以叠代出內部的值,直到清空整個生成器

  • range()在底層就是用生成器實現的, 在Python2裏,range(10)生產的就是列表,所以要用xrange(10),比較節約空間,python3優化了range(),結果是類生成器, range(121212121212212)‘在python shell下可以馬上生成,但是list(range(121212121212121212))`可能會很慢甚至直接出現內存錯誤,因為列表需要將所有的值都讀進內存,但是內存分配給列表的標準內存是有限的空間,所以會出現內存錯誤,此時生成器的有點就顯現出來了

  • 生成器是一次性的,叠代完成會出現StopIteration錯誤


yield理解

  • yield的作用類似與return;
  • 當python識別到next()函數,就會開始進入函數內部執行,直到遇到yield關鍵字,然後向外部返回yield對應的值;
  • 之後的每次調用都會從yield關鍵字開始向後執行代碼,隨後從函數頭向下執行直到遇到yield返回值後就停止等待,直到遇到下一個next();
  • g.send(’a‘)可以將’a‘賦值給yield

  • 生成器實現range( )函數
def range2(end):
    count = 0
    while count < end:
        n = yield count
        count += 1

g = range2(10)
print(next(g))
print(next(g))
print(next(g))
g.send(‘stop‘)
  • 將函數變成生成器,制作fabnacci序列生成器
def fab(max_num):
    n, a, b = 0, 0, 1
    while n < max_num:
        yield b  # 把函數執行過程凍結在這一步,並把b的值返回給外面的next(函數)
        a, b = b, a+b
        n += 1

g = fab(20)
print(g)

叠代器

  • 可叠代對象(iterable):凡是可以用for循環的對象都是可叠代對象, 常見的數據集合list, tuple, set, dict, str都是可叠代對象

  • 叠代器(iterator):
  • 可以被next()調用並不斷返回下一個值的對象就是叠代器;
  • 表示的是一個數據流,一個有序序列
  • 惰性,只有在需要返回下一個數據時才會計算
  • 無法預知大小,沒有len()這個方法

  • 可叠代對象可以轉換成叠代器, 直接調用iter()函數

  • 判斷可叠代對象: isinstance(11, Iterable)

  • 判斷是否是叠代器: isinstance((i for i in range(10)), Iterator)


python 函數進階