最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python和Ruby中each循環(huán)引用變量問題(一個隱秘BUG?)

 更新時間:2014年06月04日 09:18:39   作者:  
這篇文章主要介紹了Python和Ruby中each循環(huán)引用變量問題,類似PHP的foreach中使用引用變量的問題,需要的朋友可以參考下

雖然這個問題我是在 Python 里遇到的,但是用 Ruby 解釋起來比較容易一些。在 Ruby 里,遍歷一個數(shù)組可以有很多種方法,最常用的兩種無非是 for 和 each:

復(fù)制代碼 代碼如下:

arr = ['a', 'b', 'c']

arr.each { |e|
  puts e
}

for e in arr
  puts e
end

通常我比較喜歡后者,似乎因?yàn)閷懫饋肀容^好看,不過從效率上來說前者應(yīng)該會稍微快一點(diǎn),因?yàn)楹笳邔?shí)際上是在遍歷的過程中對每個元素都調(diào)用一個 lambda 函數(shù)來做的,雖然一般情況下并不明顯,不過設(shè)置上下文并調(diào)用函數(shù)確實(shí)是有開銷的,特別是在動態(tài)語言里面(不考慮 JIT 內(nèi)聯(lián)優(yōu)化的話)。不過這次的問題并不是性能。然而確實(shí)跟“ each 對每個元素都會新建一個 scope 而 for 則不是”有關(guān)。

看下面一段代碼:

復(fù)制代碼 代碼如下:

arr = ['a', 'b', 'c']
h1 = Hash.new
h2 = Hash.new

arr.each { |e|
  h1[e] = lambda { e+'!'}
}

for e in arr
  h2[e] = lambda { e+'!' }
end

h1['a'].call # => ?
h2['a'].call # => ?

兩個 call 分別會得到什么?應(yīng)該已經(jīng)猜到了吧?分別是 'a!' 和 'c!' ,后者之所以是 'c!' 是因?yàn)?for 并沒有在循環(huán)的每一步都重新創(chuàng)建一個 scope ,因此三個 lambda 的 closure 引用到了同一個變量,而這個變量在最后一次被賦值為 'c' ,所以導(dǎo)致了這樣的后果。

問題其實(shí)出自我在用 Python 寫的一個小程序中的一段,代碼類似于這樣:

復(fù)制代碼 代碼如下:

for prop in public_props:
    setattr(proxy, 'get_%s'%prop, lambda: self.get_prop(prop))

其中 proxy 是我提供的一個代理對象,將 self 的一些公開的屬性給暴露出去,因?yàn)橐拗茖Ψ?public 的屬性的訪問,我并不想在這個 proxy 中存放任何到 self 的引用,否則在沒有訪問權(quán)限限制的 Python 里通過類似 proxy._orig_self.some_private_prop 的方式來訪問是輕而易舉的。所以最后選擇了上面那樣的做法。

不幸的是,由于像剛才所說的那樣,for 并沒有每次都單獨(dú)創(chuàng)建 scope ,因此 closure 全部引用到了同一個變量上,導(dǎo)致所有的屬性值取出來都是最后一個屬性了??吹竭@樣詭異的 bug ,如果是在 C/C++ 里面,我肯定要懷疑是內(nèi)存或者指針的問題了。不過想了半天才終于恍然大悟!不過 Python 里面沒有 Ruby 那么方便的 each 可以用,lambda 用起來也很雞肋,所以最后通過定義一個局部的函數(shù)來解決了:

復(fù)制代碼 代碼如下:

def proxy_prop(name):
    setattr(proxy, 'get_%s'%prop, lambda: self.get_prop(name)
for prop in public_props:
    proxy_prop(prop)

最后,還要多嘴一句,對于之前 Ruby 那個例子,如果把 each 和 for 的執(zhí)行順序顛倒過來,會得到不同的結(jié)果:

復(fù)制代碼 代碼如下:
arr = ['a', 'b', 'c']
h1 = Hash.new
h2 = Hash.new

for e in arr
  h2[e] = lambda { e+'!' }
end

arr.each { |e|
  h1[e] = lambda { e+'!'}
}

h1['a'].call # => 'c!'
h2['a'].call # => 'c!'

現(xiàn)在兩個都是 'c!' 了!這是因?yàn)?Ruby 1.8 的實(shí)現(xiàn)里面 block 的參數(shù)可以對局部變量或者全局變量之類的任何東西進(jìn)行賦值,而不是通常意義上的一個 lambda 函數(shù)的參數(shù)那么簡單。由于前面的 for 語句在當(dāng)前作用域創(chuàng)建了一個 e 作為局部變量,因此 each 就直接對這個局部變量進(jìn)行賦值了,這樣,每次引用到的又變成了同一個東西,導(dǎo)致了一個隱秘的 Bug !

值得慶幸的是,block 的這個“特性”在 Ruby 1.9 中已經(jīng)被去除了,block 的參數(shù)只能是正常參數(shù),所以就不再存在這樣的問題了。希望 1.9 盡快普及吧!

相關(guān)文章

  • 將imagenet2012數(shù)據(jù)為tensorflow的tfrecords格式并跑驗(yàn)證的詳細(xì)過程

    將imagenet2012數(shù)據(jù)為tensorflow的tfrecords格式并跑驗(yàn)證的詳細(xì)過程

    這篇文章主要介紹了將imagenet2012數(shù)據(jù)為tensorflow的tfrecords格式并跑驗(yàn)證,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • Python中生成不重復(fù)ID的方法小結(jié)

    Python中生成不重復(fù)ID的方法小結(jié)

    在軟件開發(fā)中,生成不重復(fù)的ID是一個常見的需求,Python中提供了多種方法來生成不重復(fù)的ID,本文將介紹幾種常見且實(shí)用的方法,希望對大家有所幫助
    2025-01-01
  • Python使用missingno模塊輕松處理數(shù)據(jù)缺失

    Python使用missingno模塊輕松處理數(shù)據(jù)缺失

    missingno是一個基于Python的開源數(shù)據(jù)可視化工具,旨在幫助數(shù)據(jù)分析師和科學(xué)家更好地理解和處理數(shù)據(jù)缺失,下面我們就來看看如何使用missingno處理數(shù)據(jù)缺失吧
    2024-02-02
  • Python3.10.4激活venv環(huán)境失敗解決方法

    Python3.10.4激活venv環(huán)境失敗解決方法

    這篇文章主要介紹了Python3.10.4激活venv環(huán)境失敗解決方法的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • Python日志模塊Logging使用指北(最新推薦)

    Python日志模塊Logging使用指北(最新推薦)

    Logging模塊是Python中一個很重要的日志模塊,它提供了靈活的日志記錄功能,廣泛應(yīng)用于調(diào)試、運(yùn)行狀態(tài)監(jiān)控、錯誤追蹤以及系統(tǒng)運(yùn)維中,這篇文章主要介紹了Python日志模塊Logging使用指北,需要的朋友可以參考下
    2025-04-04
  • python實(shí)現(xiàn)批量監(jiān)控網(wǎng)站

    python實(shí)現(xiàn)批量監(jiān)控網(wǎng)站

    本文給大家分享的是一個非常實(shí)用的,python實(shí)現(xiàn)多網(wǎng)站的可用性監(jiān)控的腳本,并附上核心點(diǎn)解釋,有相同需求的小伙伴可以參考下
    2016-09-09
  • Python利用PyQT5設(shè)置鬧鐘功能

    Python利用PyQT5設(shè)置鬧鐘功能

    這篇文章主要介紹了通過PyQt5實(shí)現(xiàn)設(shè)置一個小鬧鐘的功能,到了設(shè)置的時間后可以響起一段音樂來提醒。感興趣的小伙伴可以跟隨小編一起試一試
    2022-01-01
  • 超實(shí)用的 30 段 Python 案例

    超實(shí)用的 30 段 Python 案例

    Python是目前最流行的語言之一,它在數(shù)據(jù)科學(xué)、機(jī)器學(xué)習(xí)、web開發(fā)、腳本編寫、自動化方面被許多人廣泛使用。這篇文章主要介紹了超實(shí)用的 30 段 Python 案例,需要的朋友可以參考下
    2019-10-10
  • Python簡單實(shí)現(xiàn)阿拉伯?dāng)?shù)字和羅馬數(shù)字的互相轉(zhuǎn)換功能示例

    Python簡單實(shí)現(xiàn)阿拉伯?dāng)?shù)字和羅馬數(shù)字的互相轉(zhuǎn)換功能示例

    這篇文章主要介紹了Python簡單實(shí)現(xiàn)阿拉伯?dāng)?shù)字和羅馬數(shù)字的互相轉(zhuǎn)換功能,涉及Python針對字符串與列表的遍歷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下
    2018-04-04
  • Python進(jìn)階:生成器 懶人版本的迭代器詳解

    Python進(jìn)階:生成器 懶人版本的迭代器詳解

    這篇文章主要介紹了Python進(jìn)階:生成器 懶人版本的迭代器詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-06-06

最新評論

南充市| 遂川县| 得荣县| 乌兰察布市| 民县| 嘉定区| 南丰县| 河津市| 长顺县| 湖南省| 资中县| 柳河县| 靖州| 拉孜县| 赤峰市| 屏山县| 靖西县| 察哈| 灵宝市| 石林| 晋江市| 武安市| 息烽县| 堆龙德庆县| 根河市| 营山县| 灌南县| 嘉善县| 峡江县| 卢龙县| 栾川县| 濮阳县| 屏东市| 长宁县| 方正县| 文水县| 武山县| 旬阳县| 武穴市| 昌图县| 岳池县|