【2020Python修煉記18】Python語法入門—函數對象+函數的嵌套+閉包函數

来源:https://www.cnblogs.com/bigorangecc/archive/2020/03/20/12530965.html
-Advertisement-
Play Games

目錄 1、函數對象 2、函數嵌套 3、閉包函數 3.1 什麼是閉包函數 3.2 如何定義閉包函數 3.3 為何要有閉包函數——閉包函數的應用場景 1、函數對象 函數對象:指的是函數可以被當做’數據’來處理。 具體可以分為四個方面的使用: (1)函數可以被引用 (2)函數可以作為容器類型的元素 (3) ...


 

目錄

1、函數對象

2、函數嵌套

3、閉包函數

3.1 什麼是閉包函數

3.2 如何定義閉包函數

3.3 為何要有閉包函數——閉包函數的應用場景

 

1、函數對象

函數對象:指的是函數可以被當做’數據’來處理。

# func=記憶體地址

def func():
    print('from func')

func()

輸出結果: from func

 

具體可以分為四個方面的使用:

(1)函數可以被引用

# func=記憶體地址
def func():
    print('from func')

f=func  # 將func的記憶體地址傳給 f

print(f,func)  #輸出的是 f func 的記憶體地址
f() #調用函數 f


輸出結果:
<function func at 0x000001CF11CCA0D0> <function func at 0x000001CF11CCA0D0>
from func

 

(2)函數可以作為容器類型的元素

 

# func=記憶體地址
def func():
    print('from func')

l=[func,]
print(l)
l[0]()

dic={'k1':func}
print(dic)
dic['k1']()

輸出結果:
[<function func at 0x000001B6BC12A0D0>]
from func
{'k1': <function func at 0x000001B6BC12A0D0>}
from func

 

(3)函數可以作為參數傳入另外一個函數

def func():
    print('from func')

def foo(x):      #  foo(func),  x = func的記憶體地址
    print(x)      #先輸出func 的記憶體地址
    x()             # x=func的記憶體地址,x()相當於 func()

foo(func)        # foo(func的記憶體地址) #調用函數foo


輸出結果:
<function func at 0x000001C3AEF4A0D0>
from func

 

# func=記憶體地址
def func():
    print('from func')

def foo(x):     # x = func的記憶體地址
    # print(x)
    x()

foo(func)       #即  foo(func的記憶體地址)

輸出結果:
from func

 

(4)函數的返回值可以是一個函數 

# func=記憶體地址
def func():
    print('from func')

def foo(x): # x=func的記憶體地址
    return x # return func的記憶體地址

res=foo(func) # foo(func的記憶體地址)
print(res) # res=func的記憶體地址

res()

輸出結果:
<function func at 0x000001C3AEF4A0D0>
from func

 

2、函數的嵌套

(1)函數的嵌套定義:在函數內定義其他函數

def f1():
    def f2():
        pass

 

(2)函數的嵌套調用:在調用一個函數的過程中又調用其他函數

def max2(x,y):
    if x > y:
        return x
    else:
        return y


def max4(a,b,c,d):
    # 第一步:比較a,b得到res1
    res1=max2(a,b)
    # 第二步:比較res1,c得到res2
    res2=max2(res1,c)
    # 第三步:比較res2,d得到res3
    res3=max2(res2,d)
    return res3

res=max4(1,2,3,4)
print(res)

好大一顆慄子:

# 圓形
# 求圓形的求周長:2*pi*radius
def circle(radius,action=0):
    from math import pi

    def perimiter(radius):
        return 2*pi*radius

  # 求圓形的求面積:pi*(radius**2)
    def area(radius):
        return pi*(radius**2)

    if action == 0:
        return 2*pi*radius

    elif action == 1:
        return area(radius)

circle(33,action=0)

 

3、閉包函數

【大前提】

基於函數對象的概念,可以將函數返回到任意位置去調用,

但作用域的關係是在定義完函數時就已經被確定了的,與函數的調用位置無關。

也就是說函數被當做數據處理時,始終以自帶的作用域為準。

 

閉包函數=名稱空間與作用域+函數嵌套+函數對象
  核心點:名字的查找關係是以函數定義階段為準

 

 (1)什麼是【閉包函數】

 函數被當做數據處理時,始終以自帶的作用域為準。若內嵌函數包含對外部函數作用域(而非全局作用域)中變數的引用,那麼該’內嵌函數’就是閉包函數,簡稱閉包(closures)。

"閉"函數指的該函數是內嵌函數

"包"函數指的該函數包含對外層函數作用功能變數名稱字的引用(不是對全局作用域)

因而無論在何處調用閉包函數,使用的仍然是包裹在其外層的變數。

x=1
def outer():
    x=2
    def inner():
        print(x)
    return inner

func=outer()
func() # 結果為2

可以通過函數的closure屬性,查看到閉包函數所包裹的外部變數。

>>> func.__closure__
(<cell at 0x10212af78: int object at 0x10028cca0>,)
>>> func.__closure__[0].cell_contents
2

 

(2) 如何定義閉包函數

1)閉包函數:名稱空間與作用域的應用+函數嵌套

def f1():
    x = 33333333333333333333
    def f2():
        print(x)
    f2()


x=11111
def bar():
    x=444444
    f1()

def foo():
    x=2222
    bar()

foo()


輸出結果:
33333333333333333333

 

2)閉包函數:函數對象

def f1():
    x = 33333333333333333333
    def f2():
        print('函數f2:',x)
    return f2

f=f1()
# print(f)

# x=4444
# f()
def foo():
    x=5555
    f()

foo()

輸出結果:
函數f2: 33333333333333333333

(3)為何要有閉包函數——閉包函數的應用

兩種為函數體傳參的方式:

方式一:直接把函數體需要的參數定義成形參

def f2(x):
    print(x)

f2(1)
f2(2)
f2(3)

方式二:將值包給函數 

def f1(x): # x=3
    x=3
    def f2():
        print(x)
    return f2

x=f1(3)
print(x)

x()

又有好大一顆慄子:

import requests # 需要事先下載函數模板

傳參的方案一:
def get(url):
    response=requests.get(url)
    print(len(response.text))

get('https://www.baidu.com')
get('https://www.cnblogs.com/linhaifeng')
get('https://zhuanlan.zhihu.com/p/109056932')


傳參的方案二:
def outter(url):
    # url='https://www.baidu.com'
    def get():
        response=requests.get(url)
        print(len(response.text))
    return get

baidu=outter('https://www.baidu.com')
baidu()

cnblogs=outter('https://www.cnblogs.com/linhaifeng')
cnblogs()

zhihu=outter('https://zhuanlan.zhihu.com/p/109056932')
zhihu()


 閉包函數的這種特性有時又稱為惰性計算。使用將值包給函數的方式,在下一篇博客介紹的裝飾器中也將大有用處。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...