2016-06-21 5 views
1

私はpython 3.5を使用しています。 Pythonにはまったく新しいが、プログラミングには新しくない。棚からのクラス定義

c.py

class C: 
    def __init__(self, x): 
    self.x = x 
    def method(self): 
    print(self.x) 

import shelve 
from c import C 
db = shelve.open("DB") 
db['key1'] = C("test") 
db.close() 

init.py test.py

を次のように私は(私が実際にやっているの多くの簡易版)の3つのソースファイルを持っています
import shelve 
db = shelve.open("DB") 
obj = db['key1'] 
obj.method() # this works 
C.method(obj) # this doesn't -- 'C' not defined 
db.close() 

私はシェルビルドされたデータベースを設定するためにinit.pyを実行します。それから私はtest.pyを実行します。 obj.method()を実行することに満足しているので、明示的にインポートしていなくてもクラスCについて知っているようです(Lutzはデータベースに格納されていることを述べています)。しかし、私がCメソッド(obj)をしようとすると(私は必ずしもこのように呼び出す必要はありませんが、新しいオブジェクトを作成するためのクラスとしてCを使用することはその有用性を持っています)定義されていません。しかし、 'c import C'をtest.pyに追加すると動作します。ですから、ある意味ではCの定義について知っているようですが、やはりそうではありません。私はなぜこれが知りたいのか不思議です。

+0

:これらの行(Pythonの3.5.1でテスト済み)に沿って何か -

回避策問題のため、手動でのモジュールからクラスをインポートし、名前Cにクラスを割り当てることであろうルッツですか?確かにあなたは 'from C import C 'を意味しないのですか?モジュールまたは組み込みでまだ定義されていないすべての名前をインポートする必要があります。 – Kupiakos

+0

はい、私は 'from import C'を意味しました。それを修正します。なぜ私は1つのケースでインポートする必要はないが、もう1つのケースでインポートする必要があるのか​​不思議です。それは私の直感に反するようです。 – Lance

+0

_ Mark Lutz著Python_プログラミング、O'Reilly発行 – Lance

答えて

4

シェルフがオブジェクトをシリアライズするとき(ピクルリングすると信じる)、後でアンピクルするためのクラスへのインポートパスが保存されます。オブジェクトを取得すると、pickleはモジュール(c)をインポートし、Cのインスタンス(元々シリアル化されたものと同等)を返します。

これまでのところ、これはあなたの観察に基づいてあなたにとって新しいことではありません。ただし、cをインポートすると、現在の名前空間にインポートされません。実際には、それをvery localized namespaceにインポートします。したがってcモジュールがインポートされている間(sys.modulesにあります)、そこにインポートしていないため、現在のネームスペースにcまたはCが見つかりません。

別の言い方をすれば、単に何かをインポートしても、プログラム内のモジュールごとににアクセスすることはできません。インポートされたモジュール(実際には有効範囲)にのみアクセス可能にします。私がosをインポートすることができますが、ちょうどosの輸入sysがすぐにsysにアクセスできるわけではありません。私はそれを使用し始める前にそれをインポートする必要があります。

>>> import os 
>>> sys 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'sys' is not defined 
>>> os.sys 
<module 'sys' (built-in)> 
>>> import sys 
>>> sys 
<module 'sys' (built-in)> 
+0

それはある意味があります。しかし、Cが現在の名前空間にない場合、 'obj.method()'はどのように実行できますか?私の現在の名前空間ではC.method _is_のようです。どのような名前空間が実際にC.methodですか? – Lance

+0

'obj'は' C'の_instance_なので、ある意味ではそれを使ってメソッドを持っていると考えることができます(実際にはそれより少し複雑です。それを使用してメソッドをルックアップします)。つまり 'type(obj)'を実行することによって 'C '(クラス)を取得できます。しかし、 'C'インスタンスは' C'ネームスペースイベントで "生きて"いますが、 'C'のインスタンスはどこにでも' C'への参照を持ちます。 – mgilson

+0

あなたの編集をありがとう。それはもっと理にかなっています。 – Lance

1

あなたが持っているものは、mgilson's answerに記載された理由では動作しません。

import shelve 
db = shelve.open("DB") 
obj = db['key1'] 
obj.method() # this works 

## Begin added code ## 
classname = obj.__class__.__name__ 
module_name = obj.__module__ 
module = __import__(module_name, globals(), locals(), [classname], 0) 
globals()[classname] = getattr(module, classname) 
## Added code end ## 

C.method(obj) # this also works now 
db.close() 
+0

あなたのコードを理解するために医者を勉強した後、私はそれをこのようにしてもよいでしょう: 'exec(" from "+ obj .__ module__ +" import "+ obj .__ class __.__ name __)' – Lance

+0

安全でないと考えられているので、私は 'exec'を避けようとしています。いずれにせよ、おめでとう、あなたは今自分の質問に答えることができます。私の答えがあなたを助けてくれたら、それを投票してください。 [_誰かが私の質問に答えたときに何をすべきですか?_(http://stackoverflow.com/help/someone-answers) – martineau

+0

ありがとう。私はできればあなたをアップアップしますが、十分な担当者はまだいません。私はあなたの反応に感謝します。 – Lance

関連する問題