7

このテストのファイルは次のとおりです。

main.py
app/
 |- __init__.py
 |- master.py
 |- plugin/
 |-  |- __init__.py
 |-  |- p1.py
 |-  |_ p2.py

アイデアは、プラグイン対応のアプリを用意することです。新しい .py または .pyc ファイルは、API に準拠するプラグインにドロップできます。

master.pyアプリ自体だけでなく、すべてのプラグインがアクセスする必要があるグローバル変数と関数を含むアプリ レベルのファイルがあります。このテストでは、「アプリ」は app/__init__.py のテスト関数で構成されます。実際には、アプリは別のコード ファイルに移動される可能性がありますがimport master、そのコード ファイルで を使用して への参照を取り込みますmaster

ファイルの内容は次のとおりです。

main.py:

import app

app.test()
app.test2()

app/__init__.py:

import sys, os

from plugin import p1

def test():
        print "__init__ in app is executing test"
        p1.test()

def test2():
        print "__init__ in app is executing test2"
        scriptDir = os.path.join ( os.path.dirname(os.path.abspath(__file__)), "plugin" )
        print "The scriptdir is %s" % scriptDir
        sys.path.insert(0,scriptDir)
        m = __import__("p2", globals(), locals(), [], -1)
        m.test()

アプリ/master.py:

myVar = 0

アプリ/プラグイン/__init__.py:

<empty file>

アプリ/プラグイン/p1.py:

from .. import master

def test():
    print "test in p1 is running"
    print "from p1: myVar = %d" % master.myVar

アプリ/プラグイン/p2.py:

from .. import master

def test():
    master.myVar = 2
    print "test in p2 is running"
    print "from p2, myVar: %d" % master.myVar

p1モジュールを明示的にインポートするため、すべてが期待どおりに機能します。ただし、__import__p2 のインポートに使用すると、次のエラーが発生します。

__init__ in app is executing test
test in p1 is running
from p1: myVar = 0
__init__ in app is executing test2
The scriptdir is ....../python/test1/app/plugin
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    app.test2()
  File "....../python/test1/app/__init__.py", line 17, in test2
    m = __import__("p2", globals(), locals(), [], -1)
  File "....../python/test1/app/plugin/p2.py", line 1, in <module>
    from .. import master
ValueError: Attempted relative import in non-package

実行は test() 関数を介してすべて進行し、test2() がその__import__ステートメントを実行しようとするとすぐにエラーが発生します。これにより、p2 は相対インポートを実行しようとします (これ、p1 が import ステートメントを介して明示的にインポートされた場合に機能します。リコール)

using がステートメント__import__の使用とは異なることをしていることは明らかです。importPython のドキュメントでは、 import を使用すると__import__内部的にステートメントに変換されるだけであると述べられていますが、目に見える以上のことが行われている必要があります。

アプリはプラグイン ベースであるため、メイン アプリで明示的なインポート ステートメントをコーディングすることは、もちろん実現不可能です。内でインポート自体を使用する

ここで何が欠けていますか?を使用してモジュールを手動でインポートするときに、Python を期待どおりに動作させるにはどうすればよい__import__ですか? 相対インポートの考え方を完全に理解していないか、インポートが発生している場所 (つまり、コード ファイルのルートではなく関数内) に関して何かが欠けているようです。

編集:次の可能性のある解決策が見つかりましたが、失敗しました:

m = __import__("p2",globals(),locals(),"plugin")

(上記とまったく同じエラーを返します)

m = __import__("plugin",fromlist="p2")

(app.plugin.p2 ではなく、app.plugin への参照を返します)

m = __import__("plugin.p2",globals(),locals())

(app.plugin.p2 ではなく、app.plugin への参照を返します)

import importlib
m = importlib.import_module("plugin.p2")

(戻り値:)

Traceback (most recent call last):
  File "main.py", line 4, in <module>
    app.test2()
  File "....../python/test1/app/__init__.py", line 20, in test2
    m = importlib.import_module("plugin.p2")
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
ImportError: No module named plugin.p2
4

3 に答える 3

5

同様の問題がありました。
__import__すべての親__init__.pyファイルが空の場合にのみ、サブモジュールをインポートします。代わりに importlib を使用する必要があります

import importlib

p2 = importlib.import_module('plugin.p2')
于 2013-06-27T13:57:20.077 に答える
2

次の構文を試しましたか:

Pythonのインポート機能の正しい使い方 __import__()

それは同様の問題で私のために働いた...

于 2014-11-27T11:14:36.483 に答える
1

解決策が見つからなかったので、プログラムを再構築することにしました。

私がしたことは、メインアプリをクラスとしてセットアップすることでした。次に、各プラグインもクラスに変更しました。次に、 importを使用してプラグインをロードするときに、定義済みの名前を持つ各プラグイン内のクラスもインスタンス化し、メイン アプリ クラスへの参照を渡します。

これは、参照を使用するだけで、各クラスが変数をホスト クラスに直接読み取って操作できることを意味します。ホスト クラスがエクスポートするものはすべて、すべてのプラグインからアクセスできるため完全に柔軟です。

これはより効果的であることが判明し、相対パスなどに依存しません。また、理論的には、1 つの Python インタープリターがホストアプリの複数のインスタンスを同時に (たとえば、異なるスレッドで) 実行でき、プラグインが正しいホスト インスタンスを参照し直すこともできます。

基本的に私がやったことは次のとおりです。

main.py:

import os, os.path, sys

class MyApp:

    _plugins = []

    def __init__(self):
        self.myVar = 0

    def loadPlugins(self):
        scriptDir = os.path.join ( os.path.dirname(os.path.abspath(__file__)), "plugin" )   
        sys.path.insert(0,scriptDir)
        for plug in os.listdir(scriptDir):
            if (plug[-3:].lower() == ".py"):
                m = __import__(os.path.basename(plug)[:-3])
                self._plugins.append(m.Plugin(self))

    def runTests(self):
        for p in self._plugins:
            p.test()

if (__name__ == "__main__"):
    app = MyApp()
    app.loadPlugins()
    app.runTests()

プラグイン/p1.py:

class Plugin:

    def __init__(self, host):
        self.host = host

    def test(self):
        print "from p1: myVar = %d" % self.host.myVar

プラグイン/p2.py:

class Plugin:

    def __init__(self, host):
        self.host = host

    def test(self):
        print "from p2: variable set"
        self.host.myVar = 1
        print "from p2: myVar = %d" % self.host.myVar

たとえば、インポートされた各 .py ファイルを検証して、それが実際にプラグインであるかどうかを確認するなど、これを改善する余地があります。しかし、これは期待どおりに機能します。

于 2013-06-30T00:18:55.797 に答える