6

私はPythonを初めて使用しますが、かなり長い間私を悩ませてきたことがあります。MarkLutzによる「LearningPython」で、fromステートメントを使用してモジュールに存在する名前をインポートすると、最初にモジュールがインポートされ、次に新しい名前(つまり、関数、クラスなどの名前)が割り当てられることを読みました。インポートされたモジュールに存在します)、delステートメントを使用してモジュールオブジェクトを削除します。しかしfrom、それ自体がインポートされていないインポートされたモジュール内の名前を参照する名前を使用してインポートしようとするとどうなりますか?mod1.py2つのモジュールがあり、次の例を考えてみましょうmod2.py

#mod1.py
from mod2 import test
test('mod1.py')        

#mod2.py
def countLines(name):
    print len(open(name).readlines())

def countChars(name):
    print len(open(name).read())

def test(name):
    print 'loading...'
    countLines(name)
    countChars(name)
    print '-'*10

次に、mod1を実行またはインポートするとどうなるかを確認します。

>>>import mod1

loading...
3
44
----------

ここで、関数をインポートして実行すると、またはをtestインポートしていなくても正常に実行され、ステートメントはすでにモジュールオブジェクトを削除していました。countCharscountLinesfrommod2

したがって、私が述べた問題を考慮しても、このコードが機能する理由を基本的に知る必要があります。

編集:答えたすべての人に感謝します:)

4

6 に答える 6

6

すべての関数には、__globals__グローバル変数と関数を検索する環境の参照を保持する属性があります。

次に、test関数はのグローバル変数にリンクされますmod2。そのため、関数をインポートするモジュールで同じ名前の新しい関数を作成した場合でも、インタプリタを呼び出すcountLinesと常に正しい関数が見つかります。

于 2012-08-14T18:13:12.643 に答える
4

私はあなたがPythonが扱う方法と格闘していると思いますnamespaces。入力from module import thingすると、現在の名前空間に移動しますthingmoduleしたがって、この例では、mod1がインポートされると、コードは次の順序で評価されます。

from mod2 import test #Import mod2, bring test function into current module namespace
test("mod1.py")  #run the test function (defined in mod2)

そして今mod2のために:

#create a new function named 'test' in the current (mod2) namespace 
#the first time this module is imported.  Note that this function has
#access to the entire namespace where it is defined (mod2).
def test(name):  
    print 'loading...'
    countLines(name)
    countChars(name)
    print '-'*10

これらすべてが重要である理由は、Pythonでは名前空間にプルしたいものを正確に選択できるためです。たとえば、module1関数を定義するaがあるとしますcool_func。今、あなたは別のモジュール(module2)を書いています、そしてそれはmodule2関数cool_funcも持っているのでそれを作ります。Pythonを使用すると、これらを個別に保持できます。あなたmodule3ができること:

import module1
import module2
module1.cool_func()
module2.cool_func()

または、次のことができます。

from module1 import cool_func
import module2 
cool_func() #module1
module2.cool_func()

またはあなたがすることができます:

from module1 import cool_func as cool
from module2 import cool_func as cooler
cool()  #module1
cooler() #module2

可能性は続く...

うまくいけば、私のポイントは明確です。モジュールからオブジェクトをインポートするときは、現在の名前空間でそのオブジェクトを参照する方法を選択しています。

于 2012-08-14T18:07:40.447 に答える
3

他の答えはこれよりも明確に表現されていますが、以下を実行すると、それを確認でき、countChars実際countLinesには両方とも次のように定義されtest.__globals__ます。

from pprint import pprint
from mod2 import test

pprint(test.__globals___)
test('mod1')

インポートすると、でtest定義された他のグローバルがもたらされ、mod2必要なものすべてをインポートする必要がないことを心配せずに関数を実行できることがわかります。

于 2012-08-14T18:12:53.697 に答える
1

GUIDEからPYTHONNAMESPACESまで、

モジュールには独自のグローバル名前空間がありますが、これは、モジュール内のどこからでもすべての名前を使用できることを意味するわけではありません。スコープとは、プレフィックスなしで名前空間にアクセスできるプログラムの領域を指します。スコープは、モジュール内でスコープが提供する分離にとって重要です。動作中のスコープはいつでもあります。現在の関数のスコープ、モジュールのスコープ、そしてPythonビルトインのスコープです。このスコープのネストは、ある関数が別の関数内の名前にアクセスできないことを意味します。

名前空間は、名前を裏返しに検索することもできます。これは、モジュールのグローバル名前空間で宣言された特定の名前がある場合、他の関数がグローバル名を取得することを確認しながら、関数内でその名前を再利用できることを意味します。もちろん、名前の前に「global」キーワードを付けることで、関数にグローバル名を使用させることができます。ただし、これを使用する必要がある場合は、クラスとオブジェクトを使用する方がよい場合があります。

于 2012-08-14T18:11:35.627 に答える
1

各モジュールには独自のスコープがあります。内では、名前または(または)mod1を使用できません。countLinescountCharsmod2

mod2それ自体は、他の場所にインポートされる方法の影響をほとんど受けません。その中で定義されているすべての名前は、モジュール内で使用できます。

参照しているWebページに、モジュールオブジェクトがdelステートメントとともに削除されていると実際に記載されている場合、それは誤りです。del名前を削除するだけで、オブジェクトは削除しません。

于 2012-08-14T18:07:37.700 に答える
1

ステートメントはモジュール全体をメモリにロードするimportため、test()関数は正常に実行されました。

しかし、ステートメントを使用したので、とを直接from使用することはできませんが、確実に呼び出すことができます。countLinescountCharstest

fromステートメントは基本的にモジュール全体をロードし、インポートされた関数、変数などをグローバル名前空間に設定します。

たとえば。

>>> from math import sin
>>> sin(90)               #now sin() is a global variable in the module and can be accesed directly
0.89399666360055785
>>> math
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    math
NameError: name 'math' is not defined
>>> vars()  #shows the current namespace, and there's sin() in it
{'__builtins__': <module '__builtin__' (built-in)>, '__file__': '/usr/bin/idle', '__package__': None, '__name__': '__main__', 'main': <function main at 0xb6ac702c>, 'sin': <built-in function sin>, '__doc__': None}

単純なファイルfile.pyを考えてみましょう。

def f1():
   print 2+2

def f2():
   f1()

f2のみをインポートします。

>>> from file import f2
>>> f2()
4

インポートしf2()なかったのですが、モジュールがメモリにロードされているために正常にf1()実行されましたが、アクセスすることはできますが、モジュールの他の部分にアクセスすることはできます。f1()f2()f2()

于 2012-08-14T18:08:28.583 に答える