1. 程式人生 > >python go 延遲呼叫的多個閉包捕獲同一變數的問題

python go 延遲呼叫的多個閉包捕獲同一變數的問題

def mult():
	return [lambda x : x * i for i in range(4)]
for ele in mult():
	print(ele(2))

lambda 先捕獲上下文環境中的變數構成可呼叫物件,真正的呼叫在後邊顯式的呼叫處。問題在於 lambda 捕獲的是變數的引用(一個地址對應的記憶體),而不是捕獲時,變數的值,實際上這個值在捕獲之後可以被修改。所以實際上 3 個 lambda 捕獲的是同一個 i,i 最終對應的值為 3.

x = 3
f = lambda y : x * y
f(4)

x = 4
f(4)

第一次輸出 12,第二次輸出 16,再看上邊的問題,最終將輸出

6
6
6
6

解決的辦法就在於新增一個臨時的變數:

def mult():
	return [lambda x, y = i : x * y for i in range(4)]
for ele in mult():
	print(ele(2))

此時,便能輸出:

0
2
4
6

go 的匿名函式同樣有這個問題:

func main() {
	
	var s []func(int) int
	for i := 0; i < 4; i++ {
		s = append(s, func(x int) int{
			return x * i
		})
	}
	
	for _, f := range s{
		fmt.Println(f(2))
	}
}

小差異:跳出迴圈時,i 的值是 4;而在 python 的列表生成式 for i in range(4) 當中,迭代停止時,i 的值是 3. 所以此處 go 的輸出為:

8
8
8
8


解決辦法一樣是新增臨時變數:

func main() {
	
	var s []func(int) int
	for i := 0; i < 4; i++ {
		j := i
		s = append(s, func(x int) int{
			return x * j
		})
	}
	
	for _, f := range s{
		fmt.Println(f(2))
	}
}

此時可以得到想要的結果:

0
2
4
6

實際上根據詞法作用域,新增的臨時變數可以直接取名為 i,此時的 i 將遮蔽外層作用域的 i.

總結:python 和 go 中的匿名函式的捕獲都是引用語義上的捕獲(go本身只有值語義,map,slice,chan 說是傳引用,實質只是一個淺拷貝而已),所以捕獲的變數在被捕獲之後在匿名函式外被修改,匿名函式將受影響。

題外話,因為 C++ 中的 lambda 同時支援值捕獲和引用捕獲兩種方式,而按值捕獲,捕獲的變數的值就是捕獲的當時變數的值,這個值捕獲之後將不受外邊作用域的影響。當然不加 mutable 修飾,這個不過的變數在 lambda 內部也不能被修改。

    uint32_t i = 0;
    auto f = [i]() mutable
    {
        std::cout << "in f : " << i << "\n";
        ++i;
    };

    ++i;

    f();
    std::cout << "after f : " << i << "\n";

相關推薦

python go 延遲呼叫捕獲同一變數的問題

def mult(): return [lambda x : x * i for i in range(4)] for ele in mult(): print(ele(2)) lambda 先捕獲上下文環境中的變數構成可呼叫物件,真正的呼叫在後邊顯式的呼叫處。問題在於

Python呼叫jarby jpype

最近在看如何接入java的API 很多文章介紹了jpype。接入API後還想知道如何接入兩個或多個jar包,結果網上似乎沒有查到。自己試過之後發現只要這麼做就可以了:if __name__ == "__main__": jarpath=os.path.join(os.

go語音基礎之捕獲外部變數特點

1、閉包捕獲外部變數特點 示例: package main //必須 import "fmt" func main() { a := 10 str := "mike" func() { //閉包以引用方式捕獲外部變數 a = 666 str = "go"

Python刪除list中相同元素

個人 err val pos 倒序 pan move 信息 style pop和remove方法都可以刪除list中的元素,個人更傾向於使用remove方法,因為在刪除過程中不會打印信息,安靜的把任務完成。 pop方法:刪除過程中會打印信息 >>>

Python--函數return

列表推導式 int abc log gpo new 方法 post 函數 # 函數如果有多個return值,那麽會把這幾個return值放到一個元組裏面返回 # def hello(a, b, c, d):# return a, b, c, d## res = he

Python 基礎第十一天(和裝飾器初識)

過程 理解 繼續 記錄 turn 格式 -s pos 變量賦值 今日內容: 函數名的應用 閉包 裝飾器的初識 裝飾器的傳參 1.函數名的應用 函數名是函數的名字. 本質:變量,特殊的變量。是函數的內存地址 函數名() 可以執行此函數 (1)單獨打印函數名,可以得到函數的內存

python 第3章 之三 ,模塊等

python閉包&LEGB法則所謂閉包,就是將組成函數的語句和這些語句的執行環境打包在一起時,得到的對象 聽上去的確有些復雜,還是用一個栗子來幫助理解一下。假設我們在foo.py模塊中做了如下定義:#foo.pyfilename = "foo.py" def call_func(f

簡簡單單說

無法 服務 AR 編程語言 函數式 outer 但是 min 概念 閉包的作用 一句話,閉包的作用:將方法存於變量。 至於閉包的原因或者目的,或者說,為什麽將方法存於變量,稍後再說。 閉包的條件 為了盡量避免用一大段話描述一個概念,我們理性一點地把閉包的條件劃分成3個:

python 推導式中if else 問題

count int 列表 foo sta ood food 別人 輸出 lis03=[[[‘food‘,‘feed‘,‘foot‘],‘good‘,[‘look‘,‘loof‘,‘like‘],‘book‘],[‘cool‘,‘our‘,‘you‘,‘how‘]]有這樣一個

13、python中的函數(與裝飾器)

屬性 新的 做的 一個 too 實現 inf 高級 器) 一、嵌套函數 函數的內部又再定義另一個函數,這個函數就叫嵌套函數,裏面含函數就叫內部函數。 示例: 二、返回函數 函數可以接收函數對象作為參數,同理函數也能返回一個函數對象作為返回值。

python函數名的運用,,叠代器

exce 耗時 inner 同時 選擇 rabl 器協 iterable from 一.函數名的運用   函數名是一個變量,但它是一個特殊的變量,與括號配合可以執行函數的變量.   1.函數名的內存地址 1 def func(): 2 print("呵呵") 3 pr

用Jenkins集成ios項目設置scheme,同一代碼自動輸出環境 實現便捷切換API環境

ios項目 bug 編譯打包 不同配置 online space 測試 jenkin spa Jenkins 安裝使用參考我的博客http://www.cnblogs.com/zhujin/p/9064820.html Xcode 配置:說明 一個schema 對應一套環境

UVALive-7197 Axles 動態規劃 問題

uva main uvalive spa %d val 好題 ble 更改 題目鏈接:https://cn.vjudge.net/problem/UVALive-7197 題意 需要生產n種(2<=n<=14)零件,每種零件可以用兩種材料制作,對這兩種材料的消耗

python函數嵌套以及的原理

一點 才會 解析器 http 標識 -- return 將不 定義 變量相關—嵌套函數 python允許創建嵌套函數。也就是說我們可以在函數裏面定義函數,而且現有的作用域和變量生存周期依舊不變。 例子: #encoding=utf-8def outer(): name

利用python腳本把文件內容放到一個文件內

tdi con linux 文件內容 內容 with open pytho xls code 說明:path是你所有文件存放的目錄,先去循環所有的文件內容,然後寫入到test.xls文件裏 import os path = ‘file‘ # path=r‘D:\file‘

PYTHON自動化Day6-函式返回值和匿名函式、列表生成式,三元運算子,os模組,sys模組,時間模組,字典排序,資料庫操作,加密(md5)

一.函式多個返回值和匿名函式 #函式返回多個值,用一個變數接收 def say(): num1=1 num2=2 num3=3 return num1,num2,num3 res=say() print(res) #打印出來是元組。 函式如果返回多個值的話,會把返回的

Python指令碼自動運營自媒體平臺,不寫稿坐等收錢,只告訴你原理

使用此方法最低成本不超過120元/年,年收入根據你所選擇垂直行業和帳號多少以及哪些平臺來決定 我所說的最低成本是針對我而言來說的,辛苦點的可以做到0成本操作,喜歡冒險的總投入不會超過5000塊錢 首先第一步就是你要有自媒體帳號,帳號和平臺不限,根據你對平臺的理解來自行選擇使用那個平臺,

python基礎知識整理4——函式

函式閉包 Function Clouse:引用了自由變數的函式既是一個閉包.這個被引用的自由變數和這個函式一同存在,即便它已經離開了創造它的環境也一樣. 比如下面的函式的返回值 def foo(): I = [] def bar(i): I.appe

Android同一套程式碼打APP並能夠在同一個手機上安裝執行

Android同一套程式碼打多個APP包並能夠在同一個手機上安裝執行 Android同一套程式碼打多個APP包並能夠==在同一個手機上安裝執行==,同時==APP名稱、桌面icon圖示也都不同== 給同一套程式碼起不同的多個包名,並把APP名稱和桌面圖示設定為

在當java有jar檔案時,如何在控制檯編譯執行

編譯 javac -cp .:/root/java/hash2/lib/mysql-connector-java-5.1.35-bin.jar:/root/java/hash2/lib/c3p0-0.9.1.1.jar *.java   執行 java -cp .: