2012-02-18 13 views
0

給定一個自定義的新樣式的python類實例,散列它並從中獲取唯一的類ID值以用於各種用途的好方法是什麼?考慮給定類實例的md5sum或sha1sum。散列一個python新樣式類實例?

我目前使用的方法是把pickles類運行並通過hexdigest運行,將結果散列字符串存儲到類屬性中(該屬性永遠不是pickle/unpickle過程的一部分,fyi)。除了現在我已經遇到了第三方模塊使用嵌套類的情況,並且沒有真正好的方法來挑選那些沒有一些黑客的東西。我覺得我錯過了一些聰明的小竅門,在某處完成這個任務。

編輯:

示例代碼,因爲它似乎是一個需要在這裏工作再上一個問題的任何牽引力。下面的類可以初始化,並且self._uniq_id屬性可以正確設置。

#!/usr/bin/env python 

import hashlib 

# cPickle or pickle. 
try: 
    import cPickle as pickle 
except: 
    import pickle 
# END try 

# Single class, pickles fine. 
class FooBar(object): 
    __slots__ = ("_foo", "_bar", "_uniq_id") 

    def __init__(self, eth=None, ts=None, pkt=None): 
     self._foo = "bar" 
     self._bar = "bar" 
     self._uniq_id = hashlib.sha1(pickle.dumps(self, -1)).hexdigest()[0:16] 

    def __getstate__(self): 
     return {'foo':self._foo, 'bar':self._bar} 

    def __setstate__(self, state): 
     self._foo = state['foo'] 
     self._bar = state['bar'] 
     self._uniq_id = hashlib.sha1(pickle.dumps(self, -1)).hexdigest()[0:16] 

    def _get_foo(self): return self._foo 
    def _get_bar(self): return self._bar 
    def _get_uniq_id(self): return self._uniq_id 

    foo = property(_get_foo) 
    bar = property(_get_bar) 
    uniq_id = property(_get_uniq_id) 
# End 




這下一個類,但是,不能因爲Bar初始化被嵌套在Foo

#!/usr/bin/env python 

import hashlib 

# cPickle or pickle. 
try: 
    import cPickle as pickle 
except: 
    import pickle 
# END try 

# Nested class, can't pickle for hexdigest. 
class Foo(object): 
    __slots__ = ("_foo", "_bar", "_uniq_id") 

    class Bar(object): 
     pass 

    def __init__(self, eth=None, ts=None, pkt=None): 
     self._foo = "bar" 
     self._bar = self.Bar() 
     self._uniq_id = hashlib.sha1(pickle.dumps(self, -1)).hexdigest()[0:16] 

    def __getstate__(self): 
     return {'foo':self._foo, 'bar':self._bar} 

    def __setstate__(self, state): 
     self._foo = state['foo'] 
     self._bar = state['bar'] 
     self._uniq_id = hashlib.sha1(pickle.dumps(self, -1)).hexdigest()[0:16] 

    def _get_foo(self): return self._foo 
    def _get_bar(self): return self._bar 
    def _get_uniq_id(self): return self._uniq_id 

    foo = property(_get_foo) 
    bar = property(_get_bar) 
    uniq_id = property(_get_uniq_id) 
# End 


我收到的錯誤是:

Traceback (most recent call last): 
    File "./nest_test.py", line 70, in <module> 
    foobar2 = Foo() 
    File "./nest_test.py", line 49, in __init__ 
    self._uniq_id = hashlib.sha1(pickle.dumps(self, -1)).hexdigest()[0:16] 
cPickle.PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup __main__.Bar failed 


nest_test.py)有兩個類,因此行號偏移量)。


酸洗需要我發現的__getstate__()方法,所以爲了完整性我也實施了__setstate__()。但考慮到已經存在的關於安全和醃製的警告,有一個更好的方法來做到這一點。


根據我到目前爲止閱讀的內容,錯誤源於Python無法解析嵌套類。它試圖查找不存在的屬性__main__.Bar。它確實需要能夠找到__main__.Foo.Bar,但沒有真正的好方法來做到這一點。我在這裏遇到了另一個SO回答,它提供了一個「詭計」來哄騙Python,但它帶着一個嚴厲的警告,認爲這種方法是不可取的,要麼使用酸洗之外的其他方法,要麼將嵌套類定義移動到外部與內部相比。

但是,我相信這個答案的原始問題是用於酸洗和取出文件。我只需要醃菜以便使用必要的hashlib函數,這些函數似乎在字節數組上運行(很像我在.NET中使用的),而酸洗(特別是cPickle)與編寫我自己的字節陣列例程相比,速度更快且優化。

回答

2

這取決於完全 ID應該有什麼屬性。

例如,你可以使用id(foo)獲得該保證是獨一無二的,只要foo是在內存中的活動的ID,或者你可以使用repr(instance.__dict__)如果所有的領域都有合理的repr值。

你需要什麼特別的?

+0

仍在學習Python,所以我不熟悉所有類的花哨。什麼,確切地說,是'id()'? – Kumba 2012-02-18 08:03:35

+0

@Kumba在CPython中,id()讓你獲得對象的內存地址。 – 2012-02-18 08:59:27

+0

@Kumba:repr建議是否不符合您的需求?這似乎是顯而易見的方式來做到這一點。 – Marcin 2012-02-18 11:10:17

0

雖然你此刻使用的是鹹菜的十六進制文件,但它使得它聽起來像是實際上並不需要與該對象相關,它只需要是唯一的。爲什麼不簡單地使用uuid模塊,尤其是uuid.uuid4來生成唯一的ID並將它們分配給對象中的uuid字段...

+0

我基本上想要的是給定對象的md5sum或sha1sum的等價物。如果對象發生變化,我會重新計算哈希以匹配。儘管目前使用mt類來解析文件中的數據並將其重新格式化爲另一種形式,然後將其寫回。如果我決定擴展這些功能,創建每個對象的散列和它所持有的數據片段似乎對於未來的開發來說是明智的。 – Kumba 2012-02-18 08:05:45

+0

爲了加入,我知道在.NET中,通過將對象轉換爲字節數組,然後將其提供給.NET的許多散列函數之一,這是可行的。我猜Python中的酸洗是一樣的。這只是第三方模塊中嵌套類的問題,它有效地呈現了pickle方法無法使用的問題。 – Kumba 2012-02-18 08:08:33

+0

Gotcha。這聽起來像從對象的屬性實際創建一個散列是有意義的,所以數據本身的值和任何元數據都是有意義的。整個對象(如醃菜)的散列將被綁定到python。只有數據和元數據按特定順序散列纔是語言不可知的。這將允許您或其他開發人員以另一種語言與您的代碼進行交互,以複製並確認您的數據簽名。 – Endophage 2012-02-18 08:11:49

相關問題