国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
深入理解 Python 內(nèi)部函數(shù)和閉包(進階)

大家好,我是安果!

本文以內(nèi)部函數(shù)為主線,深入講解內(nèi)部函數(shù)和閉包的應(yīng)用場景和原理,學(xué)會后你的 Python 水平會再上一個臺階,對工作面試或?qū)崙?zhàn)應(yīng)用都會很有幫助

本文包括:

  1. 函數(shù)是一等公民
  2. 內(nèi)部函數(shù)定義
  3. 閉包和 nonlocal 關(guān)鍵詞
  4. 應(yīng)用場景 - 封裝
  5. 應(yīng)用場景 - 函數(shù)生成器
  6. 函應(yīng)用場景 - 裝飾器
  7. 閉包實現(xiàn)原理

函數(shù)是一等公民

Python 是面向?qū)ο蟮木幊陶Z言,對象是 Python 的一等公民,我們常用的字符串str,整數(shù) int,和其他變量都是對象

函數(shù)也是對象,所以也是一等公民,這就意味著它和變量一樣

  1. 可以作為參數(shù)被傳遞
  2. 可以在函數(shù)內(nèi)部定義
  3. 可以作為函數(shù)返回值
  4. 函數(shù)可以賦值給變量
def say_hello():
    print('hello')

print(say_hello)

def say_something(some_func):
    for _ in range(3):
        some_func()

say_something(say_hello)

執(zhí)行結(jié)果:

<function say_hello at 0x7ff3d35b9160>
hello
hello
hello

內(nèi)部函數(shù)

把函數(shù)的內(nèi)部定義函數(shù),就是內(nèi)部函數(shù)(有點像廢話,但就那么個意思)

def outter():
    print('我是外部函數(shù)')
    def inner():
        print('我是outter的內(nèi)部函數(shù)')
    print('調(diào)用內(nèi)部函數(shù)')
    inner()
    print('我再次調(diào)用內(nèi)部函數(shù),自己家的想用就用,隨時用')
    inner()
    print('還可以返回給大家共用')
    return inner 

#調(diào)用外部函數(shù),并接受返回值
func = outter()

#調(diào)用outter返回的內(nèi)部函數(shù)
print('在外部調(diào)用內(nèi)部函數(shù)')
func()

注意: 調(diào)用的時候加小括號inner(),作為參數(shù)或者返回值的時候不加小括號inner,是引用這個函數(shù)對象

執(zhí)行結(jié)果:

我是外部函數(shù)
調(diào)用內(nèi)部函數(shù)
我是outter的內(nèi)部函數(shù)
我再次調(diào)用內(nèi)部函數(shù),自己家的想用就用,隨時用
我是outter的內(nèi)部函數(shù)
還可以返回給大家共用
在外部調(diào)用內(nèi)部函數(shù)
我是outter的內(nèi)部函數(shù)

閉包

如果內(nèi)部函數(shù)只是把函數(shù)定義在函數(shù)的內(nèi)部,那就沒有多大意思了,它還有一個很大的特點,正因為這個特點,它才被稱為:閉包 clsure

學(xué)過 JavaScript 的非小白同學(xué)可能會對這個概念很熟悉

內(nèi)部函數(shù)還有一個很重要的特性:

  1. 可以訪問它所屬的外部函數(shù)的局部變量,這些變量被稱為 nonlocal,或者enclosing 變量
  2. 可以攜帶這些 nonlocal 變量,讓它們不會被回收

所以說 Python 中的閉包就是內(nèi)部函數(shù),準確點說,它是使用了 nonlocal 變量的內(nèi)部函數(shù)

import random
def create_room():
    room_no = random.randint(1, 100) 
    print(f'我創(chuàng)建了房間號:{room_no}')

    def toilet():
        print(f'我是{room_no}的內(nèi)部廁所')
    print('上廁所')
    toilet()
    print('我再次上廁所,自己家的想用就用,隨時用')
    toilet()
    print('還可以共享給大家共用')
    return toilet

#調(diào)用外部函數(shù),并接受返回值
toilet = create_room()

#調(diào)用outter返回的內(nèi)部函數(shù)
print('在外部使用內(nèi)部廁所')
toilet()

print('在外部再次使用內(nèi)部廁所')
toilet()

運行結(jié)果:

我創(chuàng)建了房間號:52
上廁所
我是52的內(nèi)部廁所
我再次上廁所,自己家的想用就用,隨時用
我是52的內(nèi)部廁所
還可以共享給大家共用
在外部使用內(nèi)部廁所
我是52的內(nèi)部廁所
在外部再次使用內(nèi)部廁所
我是52的內(nèi)部廁所
  • 在調(diào)用一個 create_room 的時候臨時生成了房間號,一個局部變量 room_no
  • 在內(nèi)部函數(shù) toilet 中可以直接訪問外部函數(shù)的局部變量,這是內(nèi)部函數(shù)的特性。
  • 局部變量 room_no 本來在函數(shù)執(zhí)行完就釋放的,但由于內(nèi)部函數(shù) toilet 引用了它就不會被釋放了,在外部調(diào)用的時候仍然可以引用到,如此就形成了閉包

說的這么玄乎,其實就是內(nèi)部函數(shù)使用了外部函數(shù)的局部變量,所以局部變量被內(nèi)部函數(shù)給封存了,也就不會釋放了

nonlocal關(guān)鍵詞

內(nèi)部函數(shù)也可以改寫外部函數(shù)的變量值,但需要使用 nonlocal 關(guān)鍵詞聲明這是外部的變量。

回憶一下:函數(shù)內(nèi)部修改全局變量,需要使用 global 關(guān)鍵詞

import random

def create_room():
    room_no = random.randint(1, 100)
    print(f'我創(chuàng)建了房間號:{room_no}')

    def toilet():
        nonlocal room_no
        room_no = random.randint(1, 100)
        print(f'我是{room_no}的內(nèi)部廁所')
    
    print('上廁所')
    toilet()
    print(f'房間號:{room_no}')
    print('我再次上廁所,自己家的想用就用,隨時用')
    toilet()
    print(f'房間號:{room_no}')
    print('還可以共享給大家共用')
    return toilet


#調(diào)用外部函數(shù),并接受返回值
toilet = create_room()

#調(diào)用outter返回的內(nèi)部函數(shù)
print('在外部使用內(nèi)部廁所')
toilet()

print('在外部再次使用內(nèi)部廁所')
toilet()

使用 nonlocal 在內(nèi)部函數(shù)改變外部變量 room_no 的值,所以每次上廁所,都會改變房間號:

我創(chuàng)建了房間號:39
上廁所
我是43的內(nèi)部廁所
房間號:43
我再次上廁所,自己家的想用就用,隨時用
我是66的內(nèi)部廁所
房間號:66
還可以共享給大家共用
在外部使用內(nèi)部廁所
我是52的內(nèi)部廁所
在外部再次使用內(nèi)部廁所
我是29的內(nèi)部廁所

其實內(nèi)部函數(shù)就這么點東西了(后面再說它的實現(xiàn)原理),現(xiàn)在來看到底有什么實實在在的用處。

下面來說 3 個應(yīng)用場景:

應(yīng)用場景1 - 封裝

寫在內(nèi)部是因為只有在內(nèi)部才有用,外部根本不需要,也不想讓他們使用,就像上面的內(nèi)部廁所的例子,實際上是不可能在外面使用的,這種場景叫做 封裝

import random

def create_room():
    room_no = random.randint(1, 100)
    print(f'我創(chuàng)建了房間號:{room_no}')

    def toilet():
        print(f'歡迎進入{room_no}的VIP廁所')
        print('沖水')
        print('請君入廁')
        print('洗手')
        print('熱毛巾')
        print('歡迎下次光臨')

    print('上廁所')
    toilet()
    print('上廁所')
    toilet()
    print('上廁所')
    toilet()

#調(diào)用外部函數(shù),并接受返回值
create_room()
  • 上廁所是 create_room 所獨有的配方,不希望外面使用
  • 上廁所的過程獨有配方是比較復(fù)雜的,有必要封裝到函數(shù)內(nèi),否則每次上廁所都要重復(fù)這些代碼

再總結(jié)一下:

  1. 封裝一方面不希望對外暴露函數(shù)
  2. 也為了方便內(nèi)部的重用

應(yīng)用場景2 - 函數(shù)生成器

內(nèi)部函數(shù)可以方便的生成新的函數(shù),看這個例子:

def team_maker(type, level, temperature):
    '''
    type: 品種,如綠茶,紅茶
    level: 等級,特級,一級,二級
    temper: 溫度
    '''
    def tea(water):
        print('正在沏茶中')
        print(f'{type},{level}, {temperature}')
        print(f'{water}毫升給您沖好了')
    return tea


#創(chuàng)建符合我口味的沏茶函數(shù)
mytea = team_maker('綠茶', '特級', '66.6')
#創(chuàng)建符合她口味的沏茶函數(shù)
herteam = team_maker('紅茶', '一級', '88.8')

print('我們來一杯')
mytea(500)
herteam(300)
print('多喝點')
mytea(800)
herteam(600)
print('完了,我喝醉了...,因為有她')
  • 沏茶需要傳入多個參數(shù),有點麻煩,而每個人的口味相對比較固定
  • 我們用內(nèi)部函數(shù)創(chuàng)建了一個符合我口味的沏茶函數(shù),以后調(diào)用這個函數(shù)就行了,我也給她創(chuàng)建了一個符合她口味的沏茶函數(shù)

運行結(jié)果:

我們來一杯
正在沏茶中
綠茶,特級, 66.6
500毫升給您沖好了
正在沏茶中
紅茶,一級, 88.8
300毫升給您沖好了
多喝點
正在沏茶中
綠茶,特級, 66.6
800毫升給您沖好了
正在沏茶中
紅茶,一級, 88.8
600毫升給您沖好了
完了,我喝醉了...

應(yīng)用場景3 - 裝飾器

裝飾器,對 Python 至關(guān)重要,它也是內(nèi)部函數(shù)的主要使用場景

閉包實現(xiàn)原理

閉包攜帶了外部函數(shù)的變量,所以可以訪問這些變量,而這些變量也不會被釋放

具體是怎么實現(xiàn)的呢?答案就 1 個字:__closure__屬性

Python 給內(nèi)部函數(shù)添加了這個屬性來攜帶內(nèi)部函數(shù)用到的外部函數(shù)中的變量

import random


def create_room():
    room_no = random.randint(1, 100)
    print(f'我創(chuàng)建了房間號:{room_no}')

    def toilet():
        print(f'我是{room_no}的內(nèi)部廁所')
    return toilet


print('調(diào)用外部函數(shù)')
toilet = create_room()

print('打印一下toilet函數(shù)的變量,其中有一個是__closure__')
print(dir(toilet))
print('__closure__是一個包含它攜帶的變量的元組')
print(toilet.__closure__)
print('__closure__元組里是cell,通過cell_contents可以訪問所攜帶的變量值')
print(toilet.__closure__[0].cell_contents)

執(zhí)行結(jié)果:

import random


def create_room():
    room_no = random.randint(1, 100)
    print(f'我創(chuàng)建了房間號:{room_no}')

    def toilet():
        print(f'我是{room_no}的內(nèi)部廁所')
    return toilet


print('調(diào)用外部函數(shù)')
toilet = create_room()

print('打印一下toilet函數(shù)的變量,其中有一個是__closure__')
print(dir(toilet))
print('__closure__是一個包含它攜帶的變量的元組')
print(toilet.__closure__)
print('__closure__元組里是cell,通過cell_contents可以訪問所攜帶的變量值')
print(toilet.__closure__[0].cell_contents)

最后

你動動手,就是對我最大的鼓勵,本文內(nèi)容干貨,首先建議收藏

如果對你有幫助,請 點贊在看,轉(zhuǎn)發(fā)。謝謝!

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Python裝飾器的實現(xiàn)原理
說說 Python 中的閉包
Python3(九) 閉包
Python基礎(chǔ)之裝飾器
Python裝飾器decorator用法實例
python變量之全局變量與局部變量的使用
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服