我正在编写一个简短的代码来处理数据文件,偶然发现了lambda函数工作方式我不理解的东西。
问题在于:我有一个关键字列表,以及这些关键字出现在数据文件中的行的索引列表,并希望将某些操作应用于所述行(和/或相邻的行,因此需要索引列表而不仅仅是行列表)。
为此,我定义了一个字典,将每个关键字与一个lambda函数相关联,该函数将所需操作应用于所需行。例如:
methnames = {'acell' : lambda i : float(dat[i][1]) } #with dat the data file
(除了多个关键字和更复杂的功能)。
现在,要按照我的预期执行它,需要定义一个名为dat
的全局变量,所以我只需要放一个dat=[]
,因为我会在将定义dat
的本地范围。
除了我执行整个代码之外,我得到一个IndexError
,并且回溯告诉我,即使该lambda确实是从通常应该定义dat
的本地范围内调用的,它仍然使用全球dat
。
即使我可以解决这个问题,对于Python来说这似乎是一种非常奇怪的行为,所以我可能错过了一些东西。
以下是代码的简化版本:
dat=[]
methnames = {'acell' : lambda i : float(dat[i][1]) }
def test(dat):
return(methnames['acell'](0))
a=test([['acell',0,1,1]])
通常应该给a=0
,这是返回:
Traceback (most recent call last):
File "<ipython-input-21-cc8eb6df810c>", line 1, in <module>
runfile('/home/penwwern/Documents/mineralo/MinPhys/FrI/out/test.py', wdir='/home/penwwern/Documents/mineralo/MinPhys/FrI/out')
File "/usr/lib/python3/dist-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 699, in runfile
execfile(filename, namespace)
File "/usr/lib/python3/dist-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 88, in execfile
exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace)
File "/home/penwwern/Documents/mineralo/MinPhys/FrI/out/test.py", line 18, in <module>
a=test([['acell',0,1,1]])
File "/home/penwwern/Documents/mineralo/MinPhys/FrI/out/test.py", line 15, in test
return(methnames['acell'](0))
File "/home/penwwern/Documents/mineralo/MinPhys/FrI/out/test.py", line 9, in <lambda>
methnames = {'acell' : lambda i : float(dat[i][1]) }
IndexError: list index out of range
答案 0 :(得分:2)
Python不会检查调用者的范围,而是检查函数的定义范围。这是因为Python is lexically scoped。
In [1]: def f(): print(i)
In [2]: def f2():
...: i = 10
...: f()
...:
In [3]: f2()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-fdec4c1c071f> in <module>()
----> 1 f2()
<ipython-input-2-5ab58f8d1867> in f2()
1 def f2():
2 i = 10
----> 3 f()
4
<ipython-input-1-a5bb8b95e798> in f()
----> 1 def f(): print(i)
NameError: name 'i' is not defined
现在,我们可以在i
定义的同一范围内绑定f
:
In [4]: i = 88
In [5]: f2()
88
但是,它确实检查了关于定义范围的封闭范围:
In [6]: def f3():
...: i = 1
...: def inner():
...: print(i)
...: return inner
...:
In [7]: inner = f3()
In [8]: inner()
1
In [9]: print(i)
88
词汇范围很常见。以下是来自维基百科的更多信息:
范围界定的一个根本区别是&#34;程序的一部分&#34; 手段。在具有词法范围的语言中(也称为静态范围), 名称解析取决于源代码中的位置和 词汇上下文,由命名变量或的位置定义 功能已定义。相比之下,在具有动态范围的语言中 名称解析取决于名称时的程序状态 遇到的是由执行上下文或调用确定的 上下文。在实践中,对于词法范围,变量的定义是 通过搜索其包含的块或函数解决,然后如果那样 无法搜索外部包含块,依此类推,而使用 查询调用函数的动态范围,然后是函数 它调用了调用函数,等等,进行调用 叠加。[4]当然,在这两个规则中,我们首先寻找一个本地 变量的定义。
https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope