1. ホーム
  2. パイソン

[解決済み] グローバル変数がモジュールレベルで未定義である

2022-03-03 12:15:29

質問

(似たような、より一般的な質問がたくさんあります。それらを読んだ後、それらの解決策を試していますが、うまくいかないので、私が見ているもののより状況に特化したバージョンとしてここで質問しています)

私はC#/C++のバックグラウンドがあるため、PythonがどのようにOOPを行うのか、本当に誤解していると思います。 そこで、今まさに私がやろうとしていることがあります。

私はプロジェクトの残りの部分をセットアップするために、部分的にサニティチェックと概念実証として、2つのモジュールから始めています。 1つのモジュールは、複数のモジュールからのデータを保存しながら、私が行くときにファイルに物事を記録します(最終的にそれらをすべてパッケージ化し、要求に応じてそれらをダンプする) PyCharmでこれをすべて行い、ところでそれが示唆するエラー警告に言及し、Python 2.7を使用します。

Module 1:
  src\helpers\logHelpers.py
    class LogHelpers:
      class log:
         def classEnter():
           #doing stuff
         def __init__(self):
           self.myLog = LogHelpers.log()  #forgot to mention this was here initially
      [..] various logging functions and variables to summarize what's happening
    __builtin__.mylogger = LogHelpers

Module 2:
  src\ULTs\myULTs.py
    mylogger.myLog.classEnter()

(モジュールとルートsrcの両方が、空の イニット .pyファイル)

ということで、こちらのまったくもって素晴らしい回答によると( Python - インポートモジュールにおけるグローバル変数の可視化 ) この段階ではうまくいくはずなのですが、'mylogger' が '未解決の参照' になってしまうのです。

ということで、一つのアプローチでした。 また、よりストレートなグローバルなものも試してみました ( Pythonです。モジュール横断型変数を作るには? )

Module 1:
  src\helpers\logHelpers.py
    class LogHelpers:
      class log:
         def classEnter(self):
           #doing stuff
         def __init__(self):
           self.myLog = LogHelpers.log()  #forgot to mention this was here initially
      [..] various logging functions and variables to summarize what's happening
    mylogger = LogHelpers

  __init__.py
     __all__ = ['LogHelpers', hexlogger]
    from .logHelpers import * 

Module 2:
  src\ULTs\myULTs.py
    from helpers import mylogger
    mylogger.myLog.classEnter()

このバージョンでは、classEnter時に "parameter 'self' unfilled" というエラーが発生します。これは、myloggerが初期化されていないことを意味するようです(誤解を招くエラーコードですが、そのような意味のようです)。

そして、こんなことをやってみた。

Module 1:
  src\helpers\logHelpers.py
    class LogHelpers:
      class log:
         def classEnter(self):
           #doing stuff
         def __init__(self):
           self.myLog = LogHelpers.log()  #forgot to mention this was here initially
      [..] various logging functions and variables to summarize what's happening
    __mylogger = LogHelpers

  __init__.py
     __all__ = ['LogHelpers', hexlogger]
    from .logHelpers import * 

Module 2:
  src\ULTs\myULTs.py
    from helpers import mylogger

    def someFunction(self):
      global mylogger
      mylogger.myLog.classEnter()

そして、このバージョンでは、グローバルなmyloggerにカーソルを合わせると、「グローバル変数がモジュールレベルで未定義です」というエラーが発生します。

それから、他のモジュールがそれぞれクラスのインスタンスをトラッキングするというアイデアもあります。

それが、私がやろうとしていることの大まかなところなんです...。 私はできるだけ多くの似たような質問を読んでいますが、それらのすべてがこれらの種類の解決策(うまくいっていないようです)に戻ってくるか、または「それをしないでください」と言うようです(これは一般的に良いアドバイスですが、私は大規模プロジェクトのために複数の進行中の非静的クラスを整理しておくための望ましいPythonyの方法を本当に理解していません - それらをすべて一つのディレクトリに押し込む以外の方法です)。

感想は? (私はどれだけPythonを誤解しているのだろう?)

[EDIT] フィードバックに基づき、内部クラスを完全に削除したミニバージョンを試してみました。 OK、では、言われたことに基づいて、ローカルのミニクラスをしてみました。

class testClass:
    def __init__(self):
        self.testVar = 2
    def incrementVar(self):
        self.testVar += 1
myClass = testClass()

経由で設定します。 イニット .py

__all__ = [myClass]
from .logHelpers import myClass

他のモジュールに移動して

from helpers import myClass
class Test_LogHelpers(unittest.TestCase):
    def test_mini(self):
        myClass.incrementVar()

PyCharmを見ずに直接実行しても、Globalは何も出ません...。 NameError: name 'myClass is not defined

というわけで、まだ振り出しです :( そして、まだ状態を保存する必要があります)

[EDIT] トレースバックを追加しました。

Traceback (most recent call last):
  File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 3.4.1\helpers\pycharm\utrunner.py", line 124, in <module>    module = loadSource(a[0])
  File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 3.4.1\helpers\pycharm\utrunner.py", line 40, in loadSource    module = imp.load_source(moduleName, fileName)
  File "C:\[...mylocation...]\py\src\ULTs\LogHelpers_ULT.py", line 3, in <module>    from helpers import myClass
  File "C:\[...mylocation...]\py\src\helpers\__init__.py", line 7, in <module>
    __all__ = [myClass]
NameError: name 'myClass' is not defined

============================================================================

kk、ミニクラスで動くようになったよ。 なぜ他のアプローチ/やり方がうまくいかなかったのかわかりませんが、これで解決したようです。 (リソース http://docs.python-guide.org/en/latest/writing/structure/ , http://mikegrouchy.com/blog/2012/05/be-pythonic-__init__py.html )

**logHelpers.py**
[... some static logging functionality ...]

class testClass:
    def __init__(self):
        self.testVar = 2

    def incrementVar(self, source):
        self.testVar += 1
        mylogger.myLog.info(source + " called, new val: " + str(self.testVar))
myClass = testClass()

**test_LogHelpers_ULT.py**
import unittest

from helpers.logHelpers import myClass    

class Test_LogHelpers(unittest.TestCase):
    def test_mini(self):
        myClass.incrementVar("LogHelpers")

なぜか イニット .py (を空白にして)明示的なインポートを行うことで、うまくいきました。 テストファイルの複製を作成し、ログ出力にはヘルパーを呼び出す最初のファイルの '3' とヘルパーを呼び出す2番目のファイルの '4' が正しく出力されていました。

ダニエル・ローズマンの助けと提案に感謝します。 しかし、あなたの回答は非常に有用なフィードバックであったため、「回答あり」とさせていただきます。

解決方法は?

始める前に、PyCharmの警告は実際のPythonのエラーではないことに注意してください:もしあなたのコードを実行したら、おそらくもっと役に立つフィードバックが得られるでしょう(Pythonのような動的言語の静的解析はそこまでしかできないことを忘れないでください、多くのことは実際にコードを実行するまで解決できないのです)。

まず、なぜここでクラスを入れ子にしているのか、その理由がよくわかりません。外側のクラスは全く役に立たないように見えるので、削除してください。

self"のエラーメッセージの理由は、インスタンスメソッドを定義しているためです。 log . を作成することができます。 mylogger (ダブルアンダースコアの接頭辞は全く必要ありません) のインスタンスです。 mylogger = log() - を作成し、それをインポートするか、またはクラスをインポートして、それが使用される場所でインスタンス化します。

つまり、最初のスニペットでは、エラーメッセージは非常に明確です。 mylogger . 上記の私の推奨する方法を使用すると、次のようになります。 from helpers import mylogger を直接呼び出して mylogger.classEnter() .

最後に、その global 文は someFunction . 自分のスコープ内で名前を再割り当てし、その再割り当てをグローバルスコープに反映させる予定がない限り、名前をグローバルと宣言する必要はありません。ここではそのようなことはしないので global .

ちなみに、内側の log クラスがあります。一般的に言って、クラスはオブジェクトに何らかの状態を保存する必要がある場合にのみ有用です。ここでは、あなたのdocstringが言うように、ユーティリティメソッドのコレクションを持っています。では、なぜそれらをクラスの中に入れるのでしょうか?の中のトップレベル関数にすればいいのです。 logHelpers モジュール(ちなみに、Pythonスタイルでは lower_case_with_underscore をモジュール名として使用します。したがって、 "log_helpers.py" となります。)