2009-03-06 3 views
6

は、私は以下の難問に遭遇しています酸洗後にPython isinstanceで予期しない動作が発生するのはなぜですか?ピクルスを経由して、オブジェクトをデシリアライズ/シリアライズした後でisinstanceを評価しようとしたとき<a href="http://www.canonical.org/~kragen/isinstance/" rel="nofollow noreferrer">isinstance is harmful</a>を使用するかどうかはさておき

from __future__ import with_statement 
import pickle 

# Simple class definition 
class myclass(object): 
    def __init__(self, data): 
     self.data = data 

# Create an instance of the class 
x = myclass(100) 

# Pickle the instance to a file 
with open("c:\\pickletest.dat", "wb") as f: 
    pickle.dump(x, f) 

# Replace class with exact same definition 
class myclass(object): 
    def __init__(self, data): 
     self.data = data 

# Read an object from the pickled file 
with open("c:\\pickletest.dat", "rb") as f: 
    x2 = pickle.load(f) 

# The class names appear to match 
print x.__class__ 
print x2.__class__ 

# Uh oh, this fails...(why?) 
assert isinstance(x2, x.__class__) 

誰でisinstanceが、この中で失敗する理由にはいくつかの光を当てることができます状況?言い換えれば、なぜPythonはこれらのオブジェクトが2つの異なるクラスのものだと思いますか? 2番目のクラス定義を削除すると、isinstanceが正常に動作します。

+0

なぜあなたはクラスを置き換えていますか?同じ名前の新しいオブジェクトを作成しています。しかし、何がポイントですか? –

+0

これはおもちゃの例です。実際には、オブジェクトをピケッとし、ワイヤで送信し、反対側でアンピクルしたいとします。受信側は、私がここでデモンストレーションしようとしているクラスの別の定義を持つ必要があります。 –

+0

@Ben Hoffstein:それはすべてが1つのプロセスであるためではありません。より現実的な例を作るために2つに分解してみてください。 –

答えて

4

これはUnpicklerクラスの作品(のsite-packages/pickle.py)がどのようです。

クラスを同じ名前のクラスに置き換えた場合、klass = getattr(mod, name)は新しいクラスを返し、インスタンスは新しいクラスになりますので、isinstanceは失敗します。

+0

ありがとうございます。これは、クラス定義が物理的に異なるサーバーとクライアントの間でシリアル化されたオブジェクトを送信するという概念にどのように影響するかを理解しようとしています。 –

+0

それには影響しません。あなたは決して二つの別々の通訳者の間でisinstanceを呼ぶことはできません。したがって、彼らは異なる通訳者の異なるクラスになりますが、同じように動作します。コードを共有していると仮定します。 –

+0

ああ、ところで、決してワイヤーでピクルスを送ることはありません。 pickle.loads( "cposix \ nsystem \ np0 \ n(S'cat/etc/passwd '\ np1 \ ntp2 \ nRp3 \ n。) –

2

x.__class__x2.__class__idを印刷すると、あなたは彼らが異なっていることがわかります、あなたのコードを変更します。

$ python foo4.py 
199876736 
200015248 
4

明白な答えを、そのないので、同じクラス。

これは同じクラスですが、同じではありません。

def find_class(self, module, name): 
    # Subclasses may override this 
    __import__(module) 
    mod = sys.modules[module] 
    klass = getattr(mod, name) 
    return klass 

見つけて、クラスをインスタンス化するには:

class myclass(object): 
    pass 

x = myclass() 

class myclass(object): 
    pass 

y = myclass() 


assert id(x.__class__) == id(y.__class__) # Will fail, not the same object 

x.__class__.foo = "bar" 

assert y.__class__.foo == "bar" # will raise AttributeError 
関連する問題