2015-09-15 50 views
2

如何複製複雜對象以便我可以向其中添加新成員?當我嘗試使用deepcopy的,它失敗「TypeError: cannot serialize ......」爲什麼在複製複雜對象時deepcopy失敗

原來的問題是,我想一些成員變量添加到現有的對象,但不能因爲這樣做的結果「AttributeError: Object is fixed

所以這個想法是創建一個新的類與添加成員的原始對象的完整副本。

orig_obj = SomeSqlObject.get_root() # contents unclear, complex 

class orig_expanded(): 
    def __init__(self, replicable_object): 
     self.__dict__ = copy.deepcopy(replicable_object.__dict__) 

     self.added_member1 = None 
     self.added_list = [] 

expanded_thing = orig_expanded(orig_obj) 

,但我得到:

TypeError: cannot serialize '_io.TextIOWrapper' object 

跟帖回答進行評論, 「什麼是SomeSqlObject?」 也許我的名字是錯誤的......實際名稱混淆爲公司。這是返回表示樹的根部(某種)即樹被定義

class SomeSqlObject(ParentRegisterSet): 
    """ 
    Implements the functionality of the Device "root" Register Set. 

    """ 
    def __init__(self, db, v1, dg, ui): 
     self.__db__ = db 
     self.__dg__ = dg 
     self.__ui__ = ui 
     SomeSqlObject.__init__(self, v1, None) 

     # note: this class is now locked 
+0

是什麼'SomeSqlObject.get_root()'返回(通常情況下,你如果要創建這些對象自己......聽起來是不是一種選擇,在這裏...子類)? –

+0

我的名字可能會誤導......試圖混淆公司代碼......然而,這裏是我稱之爲SomeSqlObject類結構:類SomeSqlObject(ParentRegisterSet): 「」」 實現了設備的功能‘根’寄存器組 「」」 高清__init __(自我,DB,V1,DG,UI): 自.__ db__ = DB 自.__ dg__ = DG 自.__ ui__ = UI SomeSqlObject .__的init __(自我,V1,沒有) #注意:這個類現在被鎖定了 –

+0

好吧,這是一個失敗...也許我必須用不同的方法來回答這個問題.... –

回答

0

確定找到答案。

試圖做的時候看到最初的錯誤setattr()AttributeError: Object is fixed.這是從原始的SomeSqlObject代碼中的錯誤自定義__setatter__()這是尋找檢查位_attr_lock和預防添加成員的對象。一旦我解除鎖定,我就可以輕鬆地添加成員。

原來的問題是,我有很多的形式id0id1id3id2等類成員(叫他們的id)的每個人是一個複雜的對象也。但是,從代碼用戶的角度來看,更好的方式是使用列表類型成員id[#]來訪問它們。所以,我需要添加一個列表類型成員id[],並確保每個連續的元素指向同一個對象,通過id0id1,即指向。 id[0],id[1]

所以,我最終的代碼,以一個複雜的對象,並添加一個列表類型的成員,是。

# Below we ADD ON to the existing SqlObject with a list-type member 
# and populate the list with proper pointers to each register/register- 
# set. This is PFM! 

id_name_re = "\W*id\D*(\d+)" 

# SqlObject has a feature to block adding attributes.... This will override 
self.regs._attr_lock = None 

# add a list-type placeholder in the SqlObj for a id array 
setattr(self.regs, 'id', []) 

# now get a list of all SqlObject members called id<#> like: 
# ['id13', 'id12', 'id11', 'id10', 'id9', 'id8', 'id14 ... 
id_list = [id_member for id_member in self.regs.__dict__ if re.match(id_name_re, id_member)] 

# Sort the list since we need to place them in the new id[] list 
# sequentially 
id_list = sorted(id_list, key=h.natural_sort_key) 

# now go through the list and create a new list element and populate 
# it with the SqlObject goofy-name which is not in a list-type format 
for id_member in id_list: 
    offset = int(re.match(id_name_re, id_member).group(1)) 

    # this is NEEDED!. It causes the SqlObject to rescan and keep 
    # everything updated ('_' is kinda like /dev/null) 
    _ = eval("self.regs.id%d" % (offset)) 

    self.regs.id.append(self.regs.__dict__[id_member].__getitem__.__self__) 
1

copy.deepcopy的行爲對於不提供直接支持(通過定義__deepcopy__)類的對象的方法是到pickle然後unpickle確保創建新實例的對象。 io.TextIOWrapper(它是一個將二進制文件類對象轉換爲文本類文件對象的包裝器)不能被序列化(因爲它假定它可能具有外部/運行時狀態,例如文件中具有特定位置的文件描述符當它後來反序列化時可能無法使用)。

錯誤出現是因爲您要複製的對象包含io.TextIOWrapper,並且序列化失敗。

如果共享狀態正常,則可以將自己限制爲淺拷貝,或使用基於合成的包裝(基於__getattr__)通過包裝對象半無縫地訪問基礎對象(除了那些討厭的special methods)或者你可以嘗試分別從字典deepcopy的價值觀,只是不理你無法複製的,例如:

for attr, value in vars(replicable_object).items(): 
    try: 
     setattr(self, attr, copy.deepcopy(value)) 
    except Exception: 
     pass 
     # Alternatively, copy reference when copy impossible: 
     #setattr(self, attr, value) 

,只是希望你能不能複製的東西不是太重要。

+0

是啊...一切都是重要的在那裏,其中包括創建_io.TextIOWrapper錯誤的I/O finctionality。感謝您的幫助。找到上面的答案。 –

0
TypeError: cannot serialize '_io.TextIOWrapper' object 

此異常意味着某處,不知何故你的對象鏈接到一個文件對象,一個插座或類似的東西。

TextIOWrapper是封裝文件描述符並允許讀取/寫入unicode字符串的類。

而且,如您所見,TextIOWrapper無法複製。

1

我的猜測是你真正想要的是一個代理類,一個從谷歌例如: http://python-3-patterns-idioms-test.readthedocs.org/en/latest/Fronting.html

你會從包裝對象初始化代理類;代理類知道的屬性在本地處理;代理類不知道的屬性傳遞給包裝對象。

+0

YES ...看來正是我需要的...然後我就不用了去看看我的原來的對象,並發現__setattr__方法所使用的阻塞機制,我不得不重寫。我希望早些時候見過。 ...我將在未來以這種方式實施它。謝謝。 –