2012-04-29 18 views
3

次の2つのモジュールprog.pyとerr.pyを考慮してください。どちらも、この問題を呈するはるかに大きなプログラムの例です。私は機能をテストベンチを備えた小さなソースファイルに分ける必要があります。例外ハンドラが別のモジュールにある場合の例外

Err.pyにはテストベンチが含まれています。 progオブジェクトを生成するとき、例外がどのように呼び出されるかに応じて、例外がキャッチされるかどうかは不明です。

prog.pyが "from err import *"ステートメントでerrオブジェクトをインポートしたとしても、モジュール名は推測されていますが(間違っていますか?)、それが指すエラーは同じものではないようですモジュール自体

これはPython 2.7のバグですか、それとも意図した動作ですか?

単に最初のファイルの両方のファイルを取得し、私が何を意味するか見るためにerr.pyを実行します。..

:それが思わ

#err.py 
import prog 
import inspect 
import sys 

class myError(Exception): 
    pass 

class MySubError(myError): 
    pass 

def doError(): 
    raise MySubError 

if __name__=="__main__": 

    p=prog.prog() 


    try: 
     doError() 
    except MySubError as er: 
     print type(er) 
     print "Captured 1" 
    except Exception as er: 
     print type(er) 
     print "Not Captured 1"   

    try: 
     p.func1() 
    except MySubError as er: 
     print type(er) 
     print "Captured 2" 
    except Exception as er: 
     print type(er) 
     print "Not captured 2" 


    try: 
     p.func2() 
    except MySubError as er: 
     print type(er) 
     print "Captured 3" 
    except Exception as er: 
     print type(er) 
     print "Not captured 3" 

#prog.py 

from err import * 



class prog(object): 
    def func1(self): 
     raise MySubError 

    def func2(self): 
     doError() 

そして第二にファイルをまるでどういうわけかerrはモジュールが何であるか知っていて、例外はMySubErrorではなくerr.MySubErrorでなければなりません。

<class '__main__.MySubError'> 
Captured 1 
<class 'test.MySubError'> 
Not captured 2 
<class 'test.MySubError'> 
Not captured 3 

答えて

1

問題は、Pythonはerr.pyがあなたのメインスクリプトと同じであることを知らないということです。通常、モジュールは一度だけインポートされますが、メインスクリプトがモジュールとしてインポートされると、Pythonは混乱し、実際にはerr.pyを2回読み込みます。 (私はそれには何の正当な理由も認識していない;おそらく@Lattyはより具体的なものかもしれない)。あなたはこの単純なスクリプトで問題を見ることができます

# File: recur.py 
import recur 
print "This is the module" 

if __name__ == '__main__': 
    print "This is main" 

あなたがそれを実行した場合、モジュールは一度しか輸入されているので、あなたはないは、無限再帰を取得します。しかし、「This is the module」が2回表示されます。

メインスクリプトが(直接的または間接的に)インポートされない限り、あるモジュールから別のモジュールへの例外のインポートに問題はありません。相互に依存する2つのモジュールAとBがそれぞれ別のモジュールをインポートすることにも問題はありません:import Aを試してみてください。それぞれが一度だけロードされることがわかります。

編集:私は本当に私はちょうどあなたの例の修正を考え、あなたがモジュールとしてあなたのメインスクリプトをインポート避けるべきだと思いますけれども:

# err.py 
... 
if __name__=="__main__": 
    from prog.err import *  # add this line 

これは、彼らの持つすべての重複スクリプトクラスに置き換えられますモジュールのバージョンなど、すべてが意図したとおりに動作します。

+0

はい私はこれを知っており、意味があります。意味が分からないのは、例外のクラス名を変更することです。私はまだそれの理由を見ることができません。結局のところ、最終的には同じクラスインスタンスです。私はexecを使用していません。モジュール関数testerr.TestError()を使用して、両方のモジュールから呼び出しました。両方のモジュールがグローバルテストモジュールで動作します。 –

+0

Jason:コードを構造化したのと同じクラスインスタンスではありません。おそらくLattyとalexisは私が間違っていると私を修正することができますが、私は信じています: 'prog.py'の中で' '間違ったimport * 'を行っているので、' 'prog'の中の' 'err.py ' py'。そのため、prog.pyでは例外クラスの名前は 'err.MySubError'で、err.pyの内部では' __main __。MySubError'という名前になっています。私はあなたが実際には二つの異なる例外を上げていると信じています。 – alan

+0

@alan、あなたは間違っています。 :-)ある正規モジュールから別の正規モジュールへの例外のインポートは、期待通りに動作しますが、これまでに試してみました。問題は、Pythonがスクリプトがモジュールと同じであることを認識しないことです。私が想像できる唯一の言い訳:スクリプト名は有効なモジュール名である必要はなく、モジュールのインポートパスには場所がないため、Pythonはそれらを追跡する良い方法がありません。 – alexis

2

ここでの問題はerrは、実際に、本質的に、二つの異なるモジュールとして作用することである:私は.....インスタンス

出力のモジュールを取得することはできませんが。

Pythonで実行されるメインモジュールは、__main__と呼ばれます。実行されたすべてがその名前空間に入れられます。ここで何が起きているのかは、モジュールを別のスクリプトにインポートすることです。そのモジュールはerrと呼ばれているため、同じものとはみなされません。

これはちょっと変わったことですが、Pythonインポートシステムの一貫性を維持する必要があります。ここでの最良の答えは、スクリプト外の例外を__main__という名前で移動することです。これは基本的にここで循環インポートを作成しているので、とにかく良いデザインです。

+0

ただerr.pyの代わりに、私はerr.pyとtesterr.pyを持っている必要がありますか? 問題は、すべてのモジュールがテストフィクスチャを持つ必要があるというルールがあることです。 exec()を使ってerrのテストハーネスを呼び出すことができたと思いますが、これはちょっとハッキリです。 –

+0

OK、私はそれが矛盾しているように思えます。 MySubErrorはその型を保持し、インポートされた方法だけで名前を変更する必要がないため、例外が発生します。しかし、私がもう一度私を得るために、私はerrでtesterrをインポートし、それがすべてのシナリオで動作するテスト関数であることを発見したので、モジュールテストを外部的に動かすことができます。 –

+1

間違いなく 'exec()'を使わないと、エイリアスの問題が悪化します。スクリプトを自分自身にインポートすることは避けてください。期待通りに動作します。 Pythonは、インポート全体の名前空間を追跡するのに本当にうまくいきます。 – alexis

関連する問題