日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python avg_python闭包

發布時間:2024/9/27 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python avg_python闭包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文分為如下幾個部分

  • 什么是閉包
  • 閉包與裝飾器
  • 閉包等價——偏函數
  • 閉包等價——類
  • 閉包等價——其他
  • 閉包用于捕獲狀態值
  • 閉包等價——協程
  • 三種方法實現動態均值

什么是閉包

閉包是攜帶著一些自由變量的函數。

我們直接來看一個例子

def fun_out(a):def fun_in(b):return a + breturn fun_in fun1 = fun_out(1)

其中fun1函數是一個閉包,它攜帶著fun_out中定義的a變量,值為1。運行程序的效果是這樣的

>>> fun1 = fun_out(1) >>> fun1(3) 4 >>> fun1(6) 7>>> fun5 = fun_out(5) >>> fun5(3) 8 >>> fun5(6) 11

fun1和fun5兩個函數的定義相同,只是攜帶的自由變量不同,便成為了兩個函數。由此閉包可以作為函數工廠,生產出功能類似,但是會有細微差別的函數。

閉包用起來非常直觀,它反映了函數內調用一個變量的搜索路徑,fun_in中調用某變量會

  • 先在fun_in函數定義的局部空間中開始搜索,可以找到b
  • 如果在局部空間中找不到,則在更上層的局部空間中找,可找到a
  • 之后在全局空間中搜索,即函數外定義的變量
  • 如果還是找不到會去找python內置變量
  • 如果還是找不到則拋出異常

閉包的特點就是,如果單獨看fun_in函數的定義,不看周圍環境,則a是未被定義的;而用這種方式返回則可以將a的值內置到函數中,這就是fun_in與fun1的區別。

我們可以查看閉包中綁定的自由變量

def fun_out(a):def fun_in(b):return a + breturn fun_in>>> fun1 = fun_out(1) >>> fun1.__closure__ (<cell at 0x000001BC7FD3D768: int object at 0x0000000072C96C40>,)

另外,有兩點需要注意。第一,下面這個fun_in不是閉包,因為其中沒有調用外面的a值,調用__closure__會為None

def fun_out(a):def fun_in(b):return 1 + breturn fun_in

第二,下面這種情況a和c都會內置進fun_in中,其中c內置的值是3

def fun_out(a):c = 1def fun_in(b):return a + b + cc = 3return fun_in

第三,注意區分下面這種情況

def fun_out(a):return fun_in()def fun_in():return afun_out(1)

如果fun_in不是定義在fun_out里面,則fun_in在尋找變量a時,不會找fun_out的局部空間,而是直接到全局去找。如果代碼只是像上面這樣定義,則調用fun_out會報錯,因為fun_in找不到a這個變量;除非在全局定義一個a才能找到。

閉包與裝飾器

裝飾器是閉包的一個應用,只是攜帶的自由變量是一個函數

def print1(func):def wrapper(*args, **kw):print(1)return func(*args, **kw)return wrapper@print1 def print2():print(2)>>> print2() 1 2

@print1命令等價于print2 = print1(print2),所以裝飾器是閉包的一種應用,自由變量是一個函數,傳入和輸出使用了相同的變量名。使用@print1的好處是使編程思路更加直觀,定義好裝飾器后,如果想對這個函數添加這個功能,就裝飾上去,而不用重新思考print2傳入print1是如何調用的、返回的是什么。

閉包等價——偏函數

還是以這個閉包為例

def fun_out(a):def fun_in(b):return a + breturn fun_in fun1 = fun_out(1)

下面使用偏函數實現

from functools import partial def fun(a, b):return a + b>>> fun1 = partial(fun, b=1) >>> fun1(3) 4 >>> fun5 = partial(fun, b=5) >>> fun5(3) 8

偏函數即固定某些參數的取值,達到函數工廠的作用。

但是這種方法不夠靈活,比如下面一種情況

def fun_out(a):c = a ** 2def fun_in(b):return c + breturn fun_in fun2 = fun_out(2)

之后我們要反復使用fun2這個函數, c只有在定義fun2時計算過,不會在之后的步驟中重復計算,而使用偏函數就無法達到這種效果。這種效果下面的類也是可以達到的。

閉包等價——類

還是上面的例子,這里定義一個類來實現

class Add:def __init__(self, b):self.b = bdef __call__(self, a):return a + self.b>>> add1 = Add(1) >>> add1(3) 4 >>> add5 = Add(5) >>> add5(3) 8

類相比于普通函數的一個好處是,類可以將一些變量內置進去,讓類中定義的函數隨意調用和修改。類相比于閉包的好處在于,函數運行結束后,可以隨意調用修改屬性(自由變量);比如一個遞歸函數,想查看這個函數被調用了幾次。

閉包等價——其他

1.如果只是使用普通的函數,傳入兩個參數也可以達到類似的效果

def fun(a, b):return a + b fun(3, b=1)

但是調用時太麻煩了,應該不算實現了閉包的功能。

2.使用lambda表達式

def fun(a, b):return a + b>>> fun1 = lambda a: fun(a, 1) >>> fun1(3) 4 >>> fun5 = lambda a: fun(a, 5) >>> fun5(3) 8

相比于partial來說,lambda表達式會略顯臃腫。

閉包用于捕獲狀態值

除了函數工廠,閉包還可以用于將函數與它的狀態綁定,方便輸出函數的狀態和函數運行結果,比如輸出函數被調用的次數

def fun_out():count = 0def fun_in(something):nonlocal countcount += 1print(count, something)return fun_in>>> fun1 = fun_out() >>> fun1('first') 1 first >>> fun1('second') 2 second

這種應用可以改寫成類的形式但是不能用partial等來改寫。不過還有另一種改寫方式——協程。

閉包等價——協程

def fun():count = 0while True:something = yieldcount += 1print(count, something)>>> fun1 = fun() >>> next(fun1) >>> fun1.send('first') 1 first >>> fun1.send('second') 2 second

對yield不了解的讀者可以參考這篇文章

三種方法實現動態均值

我們要實現一個函數達到下面的效果

def running_avg(number):passrunning_avg(10) # 10 --> 10 / 1 running_avg(20) # 15 --> (10 + 20) / 2 running_avg(30) # 20 --> (10 + 20 + 30) / 3

1.類實現

class Running_avg:def __init__(self):self.total = 0self.count = 0def __call__(self, number):self.total += numberself.count += 1return self.total / self.count>>> running_avg = Running_avg() >>> running_avg(10) 10.0 >>> running_avg(20) 15.0 >>> running_avg(30) 20.0

2.閉包實現

def initial():total = 0count = 0def func(number):nonlocal totalnonlocal counttotal += numbercount += 1return total / countreturn func>>> running_avg = initial() >>> running_avg(10) 10.0 >>> running_avg(20) 15.0 >>> running_avg(30) 20.0

3.協程實現

def Running_avg():total = 0count = 0average = Nonewhile True:number = yield averagecount += 1total += numberaverage = total / count>>> running_avg = Running_avg() >>> next(running_avg) >>> running_avg.send(10) 10.0 >>> running_avg.send(20) 15.0 >>> running_avg.send(30) 20.0

參考資料

下面是本文的參考資料

  • 這篇文章對什么是閉包解釋的非常清楚
  • 閉包的應用和替代方案
  • 閉包捕獲狀態值
  • 動態均值參考fluent python一書第16章

專欄信息

專欄主頁:python編程

專欄目錄:目錄

版本說明:軟件及包版本說明

總結

以上是生活随笔為你收集整理的python avg_python闭包的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。