我正在嘗試爲只讀對象編寫一個類,它不會真正與copy
模塊一起復制,並且當它將被醃製以在進程之間傳輸時,每個進程將保留不超過一個副本,無論它將作爲「新」對象傳遞多少次。有沒有這樣的事情?用於pickle和copy-persistent對象的類?
回答
我不知道已經實現了這樣的功能。有趣的問題如下,並需要明確規範,什麼是在這種情況下發生的...:
- 進程A,使OBJ,並將其發送給B的unpickles它,到目前爲止好
- A向obj發送更改X,同時B將更改Y發送給目標對象的ITS副本,現在任一進程都會將其obj發送給其他對象,從而取消對其的訪問:要將該對象更改爲 需要在此時可見在每個過程中? A是否發送給B或反之亦然 ,即A是否「擁有」該對象?或者是什麼?
如果你不在乎,比如說因爲只有一個OWNS obj - 只允許A做更改並將obj發送給其他人,其他人不能也不會改變 - 那麼問題歸結爲唯一識別obj - 一個GUID將會做。該類可以維護一個將GUID映射到現有實例的類屬性dict(可能是一個弱值字典,以避免實例不必要地活着,但這是一個側面問題),並確保在適當時返回現有實例。
但是,如果需要將更改同步到更精細的粒度,那麼突然間它是分佈式計算的一個非常困難的問題,以及在什麼情況下需要極其小心地確定哪些情況會發生什麼規格(以及更偏執於在我們大多數人中都存在 - 分佈式編程是非常棘手的,除非幾個簡單和可證明正確的模式和習語被狂熱地追隨!)。
如果你能指定我們的規格,我可以提供一個草圖,說明如何去嘗試滿足它們。但我不會以你的名義猜測這些規格;-)。
編輯:在OP澄清,似乎所有他需要的是更好地瞭解如何控制__new__
。這很容易:請參閱__getnewargs__
- 您需要一個新式類,並使用協議2或更高版本進行酸洗(但由於其他原因,這些建議無論如何都是可行的!),然後在現有對象中使用__getnewargs__
可以簡單地返回對象的GUID __new__
必須作爲可選參數接收)。因此__new__
可以檢查GUID是否存在於該類的memo
[[weakvalue ;-)]]字典中(如果是,則返回相應的對象值) - 如果不是(或者如果GUID未通過,則意味着它不是未刪除,因此必須生成一個新的GUID),然後創建一個真正的新對象(設置其GUID ;-)並將其記錄在類級別memo
中。
順便說一句,要製作GUID,請考慮在標準庫中使用uuid模塊。
你可以簡單地使用一個與密鑰和接收器中的值相同的字典。爲了避免內存泄漏,請使用WeakKeyDictionary。
你必須更徹底地解釋。 – 2009-09-09 20:51:52
我試圖實現這一點。 @Alex Martelli和其他人,請給我評論/改進。我認爲這最終會在GitHub上結束。
"""
todo: need to lock library to avoid thread trouble?
todo: need to raise an exception if we're getting pickled with
an old protocol?
todo: make it polite to other classes that use __new__. Therefore, should
probably work not only when there is only one item in the *args passed to new.
"""
import uuid
import weakref
library = weakref.WeakValueDictionary()
class UuidToken(object):
def __init__(self, uuid):
self.uuid = uuid
class PersistentReadOnlyObject(object):
def __new__(cls, *args, **kwargs):
if len(args)==1 and len(kwargs)==0 and isinstance(args[0], UuidToken):
received_uuid = args[0].uuid
else:
received_uuid = None
if received_uuid:
# This section is for when we are called at unpickling time
thing = library.pop(received_uuid, None)
if thing:
thing._PersistentReadOnlyObject__skip_setstate = True
return thing
else: # This object does not exist in our library yet; Let's add it
new_args = args[1:]
thing = super(PersistentReadOnlyObject, cls).__new__(cls,
*new_args,
**kwargs)
thing._PersistentReadOnlyObject__uuid = received_uuid
library[received_uuid] = thing
return thing
else:
# This section is for when we are called at normal creation time
thing = super(PersistentReadOnlyObject, cls).__new__(cls, *args,
**kwargs)
new_uuid = uuid.uuid4()
thing._PersistentReadOnlyObject__uuid = new_uuid
library[new_uuid] = thing
return thing
def __getstate__(self):
my_dict = dict(self.__dict__)
del my_dict["_PersistentReadOnlyObject__uuid"]
return my_dict
def __getnewargs__(self):
return (UuidToken(self._PersistentReadOnlyObject__uuid),)
def __setstate__(self, state):
if self.__dict__.pop("_PersistentReadOnlyObject__skip_setstate", None):
return
else:
self.__dict__.update(state)
def __deepcopy__(self, memo):
return self
def __copy__(self):
return self
# --------------------------------------------------------------
"""
From here on it's just testing stuff; will be moved to another file.
"""
def play_around(queue, thing):
import copy
queue.put((thing, copy.deepcopy(thing),))
class Booboo(PersistentReadOnlyObject):
def __init__(self):
self.number = random.random()
if __name__ == "__main__":
import multiprocessing
import random
import copy
def same(a, b):
return (a is b) and (a == b) and (id(a) == id(b)) and \
(a.number == b.number)
a = Booboo()
b = copy.copy(a)
c = copy.deepcopy(a)
assert same(a, b) and same(b, c)
my_queue = multiprocessing.Queue()
process = multiprocessing.Process(target = play_around,
args=(my_queue, a,))
process.start()
process.join()
things = my_queue.get()
for thing in things:
assert same(thing, a) and same(thing, b) and same(thing, c)
print("all cool!")
- 1. windows中的pickle rpy2對象
- 2. IE7與Python Pickle對象
- 3. 使用Pickle對象,如API調用
- 4. python中的pickle隊列對象
- 5. 無法從文件加載pickle對象
- 6. 正在更新Python Pickle對象
- 7. 將python pickle對象存入mysql + django
- 8. 關於類和對象的疑問
- 9. 試圖存儲一個對象,但不能pickle ttk類
- 10. 在pickle文件中保存和加載多個對象?
- 11. 關於Cucumber/Pickle的問題
- 12. 等價於Julia中的pickle
- 13. 類和對象類
- 14. 在pickle中仍然引用的已刪除對象
- 15. 如何使用pickle來保存程序中的所有對象?
- 16. 我新使用python pickle和
- 17. Pthread對於使用類對象引用的C++類函數
- 18. 使用基於類的MySQLi對象
- 19. 使用pickle轉儲gtk.ListStore的子類
- 20. ' - >'和'。'用於對象的引用?
- 21. Django的 - 對象級別premission和基於類的通用視圖
- 22. 用於App Engine的Python中的克隆和Expando類對象
- 23. Symfony2:引用類似於請求對象的對象?
- 24. Can Pickle可以處理多個對象引用
- 25. 如何在Python 2.7中使用JSON加載Pickle對象?
- 26. 如何使用pickle從MDAnalysis模塊轉儲Universe對象?
- 27. 使用pickle時出錯,TypeError:無法泡製ElementBase對象
- 28. 對象/類的Ruby sort_by對於
- 29. 用於QT類和對象的可視化代碼檢查器
- 30. Spring和Hibernate:用於包含對象的對象的形式
道歉,@Alex Martelli,我應該提到該對象是隻讀的。 – 2009-09-09 22:02:00
@ cool-RR,那麼我提到的方法(「一個OWNS」)應該工作(如果它是隻讀的,A沒有理由多次發送它,所以你可以放棄我建議的每一部分,但也許「你的**」的意思是「只讀」是非常奇特的,並且包括**變化......在任何我能想到的SENSIBLE解釋中,這與「只讀」完全相反。 ! - )。 那麼,如果在我的基於GUID的建議中找不到任何內容,哦@ cool-rr? – 2009-09-10 05:49:58
@Alex Martelli:是的,這幾乎是我想到的方法。我試圖實現它,似乎'__new__'方法是動作所在的地方,但由於文檔稀缺,並且我不明白'__new__'方法是如何知道它是否不拆卸時間或正常的創作時間。 – 2009-09-10 10:01:03