2017-03-07 8 views
0

データファイルを処理するための短いコードを書いていて、ラムダ関数が動作する方法でわからないものを見つけました。ラムダ関数がローカルスコープを使用していません

ここに問題があります:私は、キーワードのリストと、それらのキーワードがデータファイル内に現れる行のインデックスのリストを持っていて、その行に特定の操作を適用したい(および/またはしたがって、単純に行のリストではなく、インデックスのリストが必要です)。

これを行うには、必要な操作を目的の行に適用するラムダ関数を各キーワードに関連付ける辞書を定義しました。例:

methnames = {'acell'  : lambda i : float(dat[i][1]) } #with dat the data file 

(複数のキーワードとより複雑な機能を除く)。私はdatが定義されますローカルスコープ内からこれらの関数を呼び出すと同じように、私は予想通り

は今、それを実行するために、それは定義するdatという名前のグローバル変数を持つことが必要なので、私はちょうどdat=[]を置きます。私は、全体のコードを実行する場合を除き

、私はIndexError取得し、トレースバックはそのラムダが実際に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 
+3

あなたのリストはいえ、 'lambda'がアクセスしているリストではありません –

+0

@MosesKoledoye存在しないインデックス0インデックス1に1つだけの項目(別のリスト)を持っています。 – jonrsharpe

+0

@MosesKoledoye実際には、コードを省略して訂正しても、問題は同じ – penwy

答えて

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 

今、私たちは、fが定義されているのと同じ範囲でiをバインドすることができます。

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 

In [4]: i = 88 

In [5]: f2() 
88 

しかし、それは、それが定義されている場所についてのスコープを囲んでのチェックはありません

レキシカルスコープはかなり一般的です。ここではウィキペディアからいくつかのより多くの情報がある:

スコープの根本的な違いは何 手段「プログラムの一環」です。字句スコープ(静的スコープとも呼ばれます)の言語では、 の名前解決はソースコード内の場所と、指定された変数または 関数が定義されている場所で定義される語彙コンテキスト によって異なります。対照的に、ダイナミックスコープの言語では、 という名前が実行コンテキストによって決定されるか、または コンテキストを呼び出すと、名前解決がプログラム状態に依存します。 実際には、語彙スコープでは、変数の定義は包含ブロックまたは関数を検索して を解決した後、 が外側の包含ブロックの検索に失敗したなどのようになり、一方 動的スコープでは呼び出し関数が検索された後、関数 その呼び出し関数を呼び出したなど、 スタックを呼び出す[4]もちろん、どちらのルールでも、ローカルの 変数の定義を探します。

https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope

+0

ではありません問題は実際にスコープが動作する方法の理解の欠如でした。どうもありがとう。 – penwy

+0

ここで関連する技術用語は、(Pythonが使用する)レキシカルスコープと(あなたが期待していた)ダイナミックスコープです。 – chepner

+0

@chepnerはい、それを追加する途中でした。 –

関連する問題