国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

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

2020-02-23 05:26:38
字體:
來源:轉載
供稿:網友

雖然這個問題我是在 Python 里遇到的,但是用 Ruby 解釋起來比較容易一些。在 Ruby 里,遍歷一個數組可以有很多種方法,最常用的兩種無非是 for 和 each:
代碼如下:
arr = ['a', 'b', 'c']

arr.each { |e|
  puts e
}

for e in arr
  puts e
end
通常我比較喜歡后者,似乎因為寫起來比較好看,不過從效率上來說前者應該會稍微快一點,因為后者實際上是在遍歷的過程中對每個元素都調用一個 lambda 函數來做的,雖然一般情況下并不明顯,不過設置上下文并調用函數確實是有開銷的,特別是在動態語言里面(不考慮 JIT 內聯優化的話)。不過這次的問題并不是性能。然而確實跟“ each 對每個元素都會新建一個 scope 而 for 則不是”有關。

看下面一段代碼:
代碼如下:
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 分別會得到什么?應該已經猜到了吧?分別是 'a!' 和 'c!' ,后者之所以是 'c!' 是因為 for 并沒有在循環的每一步都重新創建一個 scope ,因此三個 lambda 的 closure 引用到了同一個變量,而這個變量在最后一次被賦值為 'c' ,所以導致了這樣的后果。

問題其實出自我在用 Python 寫的一個小程序中的一段,代碼類似于這樣:
代碼如下:
for prop in public_props:
    setattr(proxy, 'get_%s'%prop, lambda: self.get_prop(prop))
其中 proxy 是我提供的一個代理對象,將 self 的一些公開的屬性給暴露出去,因為要限制對非 public 的屬性的訪問,我并不想在這個 proxy 中存放任何到 self 的引用,否則在沒有訪問權限限制的 Python 里通過類似 proxy._orig_self.some_private_prop 的方式來訪問是輕而易舉的。所以最后選擇了上面那樣的做法。

不幸的是,由于像剛才所說的那樣,for 并沒有每次都單獨創建 scope ,因此 closure 全部引用到了同一個變量上,導致所有的屬性值取出來都是最后一個屬性了。看到這樣詭異的 bug ,如果是在 C/C++ 里面,我肯定要懷疑是內存或者指針的問題了。不過想了半天才終于恍然大悟!不過 Python 里面沒有 Ruby 那么方便的 each 可以用,lambda 用起來也很雞肋,所以最后通過定義一個局部的函數來解決了:
代碼如下:
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 的執行順序顛倒過來,會得到不同的結果:

代碼如下:arr = ['a', 'b', 'c']
h1 = Hash.new
h2 = Hash.new

for e in arr

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 望都县| 射洪县| 金秀| 新民市| 巨鹿县| 启东市| 迁安市| 卓尼县| 宿州市| 林口县| 盘锦市| 麻栗坡县| 蓬莱市| 鹤庆县| 麦盖提县| 平和县| 北川| 佛坪县| 嘉兴市| 湖南省| 隆昌县| 胶州市| 赣州市| 虹口区| 望奎县| 鄂温| 南充市| 巍山| 信丰县| 丹巴县| 昌黎县| 调兵山市| 永平县| 宁陕县| 类乌齐县| 赫章县| 全南县| 上饶县| 庐江县| 沙雅县| 叙永县|