web-dev-qa-db-ja.com

グローバル変数はモジュールレベルで定義されていません

(多くの同様のより一般的な質問があり、それらを読んだ後にそれらから解決策を試していますが、それらを機能させることができないので、私が見ているもののより状況固有のバージョンとしてここに尋ねます)

私は、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 \の両方に空のinit。pyファイルがあります)

したがって、ここでの完全に素晴らしい応答( Python-インポートされたモジュール内のグローバル変数の可視性 )によると、この段階ではこれは機能しているはずですが、「mylogger」は「未解決の参照」になります

それが1つのアプローチでした。また、より単純なグローバル変数も試しました( 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の方法を実際に考えているわけではありません-以外それらすべてを1つのディレクトリに押し込みます)

考え? (ここでPythonをマングリングするのはどれほどひどいですか?)

[編集]フィードバックに基づいて、内部クラスを完全に排除したミニバージョンを試しました。わかりました。あなたの言ったことに基づいてローカルミニクラスも行いました。

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

init。pyを介して設定します

__all__ = [myClass]
from .logHelpers import myClass

他のモジュールに行き、

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

PyCharmを見る代わりに直接実行しました。グローバルなものは何もありません。NameError: name 'myClass is not defined

だからまだ正方形1で:((そしてまだ状態を保存する必要があります)

[編集]トレースバックの追加:

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")

何らかの理由で、init。pyをスキップして(空白のままにして)、明示的なインポートを実行しました。また、状態を維持しました。テストファイルの複製を作成しました。ログ出力には、ヘルパーを呼び出す最初のファイルの「3」と、ヘルパーを呼び出す2番目のファイルの「4」が正しく含まれていました。

助けと提案をしてくれたDanielRosemanに感謝します、彼らは私にもう少し正しい方向を見てもらいました。以前のものが機能しなかった理由を見つけることができれば、この言語の理解を深めることができれば幸いですが、非常に役立つフィードバックがあったので、先に進んで回答を「回答済み」としてマークします。

5
Daniel Cazan

始める前に、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」にする必要があります)。

12
Daniel Roseman