1. ホーム
  2. python

[解決済み] インポートモジュールにおけるグローバル変数の可視化

2022-05-01 03:15:32

質問

Pythonスクリプトでモジュールをインポートする際に、ちょっとした壁にぶつかった。私は、エラー、なぜそれに遭遇するのか、そしてなぜ私の問題を解決するためにこの特定のアプローチと結びついているのかを説明するために最善を尽くします(これはすぐに説明します)。

例えば、あるモジュールでユーティリティ関数やクラスを定義し、そのクラスがこの補助モジュールがインポートされるネームスペースで定義されたエンティティを参照しているとします(quot;a"をそのようなエンティティとします)。

モジュール1:

def f():
    print a

そして、メインプログラムには "a" が定義されており、そこにこれらのユーティリティをインポートしたいのです。

import module1
a=3
module1.f()

このプログラムを実行すると、以下のようなエラーが発生します。

Traceback (most recent call last):
  File "Z:\Python\main.py", line 10, in <module>
    module1.f()
  File "Z:\Python\module1.py", line 3, in f
    print a
NameError: global name 'a' is not defined

類似の質問があります で、いくつかの解決策が提案されましたが、これらは私の要件に適合するとは思えません。 ここで、私の特殊な状況を説明します。

MySQLデータベースサーバーに接続し、GUIでデータを表示・変更するPythonプログラムを作ろうとしています。きれいにするために、私は別のファイルで補助/ユーティリティのMySQL関連関数の束を定義しました。しかし、それらはすべて共通の変数を持っています。 内部 は、utilitiesモジュールで、これは カーソル オブジェクトを作成しました。 後で気づいたのですが、この カーソル オブジェクト (データベースサーバーと通信するために使用される) は、メインモジュールで定義されるべきです。 そうすれば、メインモジュールとそれにインポートされたものの両方がそのオブジェクトにアクセスできるようになります。

最終的にはこのような感じになります。

utilities_module.py です。

def utility_1(args):
    code which references a variable named "cur"
def utility_n(args):
    etcetera

そして、私のメインモジュール。

program.py。

import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor()  #cur is defined!
from utilities_module import *

そして、ユーティリティの関数を呼び出そうとすると、すぐに前述の "global name not defined" というエラーが発生するのです。

特に提案されたのは、ユーティリティ・ファイルに次のような "from program import cur" ステートメントを記述することです。

utilities_module.py。

from program import cur
#rest of function definitions

program.pyを使用します。

import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor()  #cur is defined!
from utilities_module import *

しかし、それはcyclic importとかで、結論から言うと、これもクラッシュします。そこで質問なのですが。

メインモジュールで定義された "cur" オブジェクトを、それにインポートされている補助関数から見えるようにするには、一体どうしたらいいのでしょうか?

お忙しいところありがとうございます。また、解決策が他に掲載されていたら大変申し訳ありません。もし、他の場所で解決策が掲載されていたら、大変申し訳ありません。

解決方法を教えてください。

Pythonのグローバルは、グローバル モジュールに すべてのモジュールにまたがるものではありません。(多くの人がこのことに戸惑いますが、例えばC言語では、グローバルは、明示的に static .)

これを解決する方法は、実際のユースケースによってさまざまです。


この道を進む前に、これは本当にグローバルである必要があるのか自問してみてください。もしかしたら、本当にクラスが必要かもしれません。 f をインスタンスメソッドとして、単なるフリー関数としてではなく、?そうすると、次のようなことができる。

import module1
thingy1 = module1.Thingy(a=3)
thingy1.f()


本当にグローバルが欲しいが、それは単に module1 そのモジュールに設定してください。

import module1
module1.a=3
module1.f()


一方、もし a が多くのモジュールで共有されている場合、それを別の場所に置き、全員がそれをインポートするようにします。

import shared_stuff
import module1
shared_stuff.a = 3
module1.f()

... そして、module1.pyで。

import shared_stuff
def f():
    print shared_stuff.a

ドンマイ を使用します。 from インポートは、その変数が定数であることを意図している場合を除きます。 from shared_stuff import a を使用すると、新しい a 変数に初期化された shared_stuff.a はインポート時に参照したものであり、この新しい a への代入の影響を受けません。 shared_stuff.a .


あるいは、本当にビルトインのようにどこでもグローバルであることが必要な場合は、ビルトインモジュールに追加してください。Python 2.xと3.xで正確な詳細は異なりますが、3.xではこのように動作します。

import builtins
import module1
builtins.a = 3
module1.f()