2017-12-21 16 views
1

私は関数とその関数への参照を含む辞書を持っています。データ構造内で関数名をインポートできないのはなぜですか?

def func1(): print('blah') 

dict1 = {'func1': func1} 

これらを指定の順序でPythonインタプリタに貼り付けると、すべて正常に動作します。

`>>> def func1(): print('blah') 
... 

>>> func1 
<function func1 at 0x7f8939d77730> 

>>> func1() 
blah 

>>> dict1 = {'func1': func1} 
>>> dict1['func1']() 
blah 

` 

しかし、私はファイルからdict1をインポートする場合、インタプリタはfunc1は、それが定義されていても、定義されていないと言います。ここで何が起こっている

>>> def func1(): print('blah') 
... 
>>> func1() 
blah 

>>> from dictfile import * 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/../dictfile.py", line 1, in <module> 
    dict1 = {'func1': func1} 
NameError: name 'func1' is not defined 
>>> 

dict1 = {'func1': func1} 

次に、このインタプリタへ:テキストの単一行を含む

ので、ファイルと 'dictfile.py'?

+1

実行時にfunc1の参照が存在する場合、ファイルからファイルを保存またはロードすることはできません。 –

+0

は、dictに値を代入する 'getattr(module、func1)'のようなものを使います。 –

+0

Raghavaのコメントは有益で有益であり、答えのように聞こえる。あなたは詳細を教えていただけますか? – markling

答えて

3

func1は、dictfile.pyコンテキストの範囲では定義されていません。

'func1'のグローバルスコープは、それ自身を定義することに限定されています。これは自己完結型のモジュールとして動作できるようにするためです。つまり、モジュールが動作するように動作するため、他のモジュールでインポートして実行することができます。これは、異なるモジュールがグローバル定義の異なるものに対して同じ名前を使用する場合の衝突を避けるために行われます。

のpython docsから:

したがって、モジュールの作者は、ユーザーのグローバル 変数と偶然的な衝突が起こる心配をせずにモジュール でグローバル変数を使用することができます。

ファイルをインポートステートメントで読み込むと、モジュールになります。そのモジュールがインポートするスコープを取得することは期待できません。それは独自のスコープが別個のものです。その完全性は保護されています。自分自身を定義していない場合は、それが使用する定義をインポートする必要があります。

関数を参照するディクショナリをロードするには、その関数が存在するスコープ(ファイル)で関数を定義する必要があります。

ファイルはあなたのインタプリタの現在の状態(あなたの状態はファイルにインポートされず、可能であるかどうかわかりません)について何も知らないので、関数への参照を見つけることができません。パイソンdocsによれば

各モジュールは、モジュール内で定義されたすべての関数によって グローバル・シンボル・テーブルとして使用される独自のプライベートシンボルテーブルを有しています。したがって、モジュールの作成者 は、モジュール内のグローバル変数を使用できます。 は、ユーザーのグローバル変数との偶発的な衝突を心配する必要がありません。 の場合は、 モジュールのグローバル変数に、 関数、modname.itemnameを参照するのに使用されているのと同じ表記法を使用してください。

あなたのモジュールの(ファイルの)スコープでアクセスできるようにするには、インタラクティブインタプリタの「モジュール」をインポートする必要がありますが、これは可能ではないと思います。

+0

ありがとうございます。そして、はい、それはそのように見えます。しかし、なぜこれはそうですか?直感的ではないようです。私は定義された機能を自分のスコープ内に持っています。私はそのスコープの中にその関数への参照を含む宣言を呼び出します。私はその宣言を自分のスコープに持っているので、それを参照するオブジェクトを含むスコープ内で宣言をしないのですか? delcarationは間違いなくダムファイルには作成されていません。ファイルをインポートするときに作成されます。ファイルをインポートするときに、必要な機能が自分のスコープ内で定義されます。 – markling

+0

@markling更新された回答を参照してください。それを説明するのに役立つはずのPythonのドキュメントにいくつかの詳細が追加されました。 –

+1

ありがとう、@ Pedro-von-Hertwig。私はあなたの答えを編集してその部分を詳述しました。私はこの問題を理解するのに最も有益であると感じました。 – markling

3

各モジュールは名前空間を定義しているため、モジュール内の「グローバル」変数は実際にそのモジュールにスコープされます。別のモジュールがそれらのモジュールにアクセスできますが、名前を定義したモジュールを使用してアクセスする必要があります。

インタラクティブセッションで実行する場合、作成するオブジェクトは__main__という特別なモジュールに追加されます。別のモジュールからインポートできますが、これはお勧めしません。唯一の学習目的のために一例として

:実世界のプログラムで

$ cat dictfile.py 
from __main__ import func1 
dict1 = {'func1': func1} 

$ python 
Python 2.7.10 (default, Jul 30 2016, 19:40:32) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> def func1(): print('blah') 
... 
>>> from dictfile import dict1 
>>> dict1 
{'func1': <function func1 at 0x102735c08>} 
>>> dict1['func1']() 
blah 

、あなたはこのような循環依存を避けるべきです。しかし、1つのモジュールから関数をインポートし、別のモジュールのデータ構造にアセンブルしてから、3つ目のモジュールのデータ構造を使用することができます。

プログラムの各部分の依存関係については、実装は抽象化のみに依存し、抽象化は他の抽象化のみに依存する必要があります。

+0

はい、このcicularの依存関係は私が作成したものであり、すぐに別の手段で同じ目的を達成するために何をしなければならないかについての将来の考慮のために無視されます。ありがとうございました。 – markling

関連する問題