標籤:

一個對Python初學者難以理解的作用域代碼

Python學習手冊上有一段代碼,知乎上也有人提出這個問題,Python學習手冊上也有解釋。

但追求上進的朋友,一定要查明真相,是好事,聽黃哥下面的分解。

# coding:utf-8nnndef make_actions():n acts = []n for i in range(5):n acts.append(lambda x: i ** x)n return actsnnfoo = make_actions()nprint(foo[0](2))nprint(foo[1](2))nprint(foo[3](2))nprint(foo[3](2))nn# 16n# 16n# 16n# 16n

結果都是16,書上說,循環後,最後調用foo這個列表中的函數時,都是調用的最後的i的值為

4,所以結果都為16。

這個問題進一步探討,這個是一個典型的閉包問題。請看下面的代碼。

# coding:utf-8nnndef make_actions():n """黃哥說明,這個是Python2,如果是3 func_closuren 需要修改為__closure__n """"n acts = []n for i in range(5):n acts.append(lambda x: i ** x)n return actsnnfoo = make_actions()nprint(foo[0].func_closure[0].cell_contents)nprint(foo[1].func_closure[0].cell_contents)nprint(foo[2].func_closure[0].cell_contents)nprint(foo[3].func_closure[0].cell_contents)n# 4n# 4n# 4n# 4n

Python2 中func_closure 返回閉包引用外部函數的變數,這個匿名函數lambda x: i ** x

引用了make_actions函數的i值,當函數調用時foo[0].func_closure[0].cell_contents 這個表示i值為4 所以結果為16.

如果想得到make_actions()里函數每次循環的i值,代碼修改如下。

# coding:utf-8nnndef make_actions():n acts = []n for i in range(5):n acts.append(lambda x, i=i: i ** x)n return actsnnfoo = make_actions()nprint(foo[0](2))nprint(foo[1](2))nprint(foo[3](2))nprint(foo[4](2))n# 0n# 1n# 9n# 16n

忠言:學習中,有的時候需要適當不求甚解一下,千萬不要「太鑽牛角尖」。


推薦閱讀:

GlumPy 中文文檔翻譯:上手簡介
樹莓派Raspberry區域網視頻小車教程
Kivy中文編程指南:輸入管理
Python語法速覽與機器學習開發環境搭建

TAG:Python |