1 回答

TA貢獻(xiàn)1804條經(jīng)驗(yàn) 獲得超2個(gè)贊
這是我的解決方案:
def make_extendable(o):
"""
Return an object that can be extended via its __dict__
If it is a slot, the object type is copied and the object is pickled through
this new type, before returning it.
If there is already a __dict__, then the object is returned.
"""
if getattr(o, "__dict__", None) is not None:
return o
# Now for fun
# Don't take care of immutable types or constant for now
import copy
import copyreg
cls = o.__class__
new_cls = type(cls.__name__, (cls,), {"__module__": cls.__module__})
# Support only Python >= 3.4
pick = o.__reduce_ex__(4)
if pick[0] == cls:
# This is the case for datetime objects
pick = (new_cls, *pick[1:])
elif pick[0] in (copyreg.__newobj__, copyreg.__newobj_ex__):
# Now the second item in pick is (cls, )
# It should be rare though, it's only for slots
pick = (pick[0], (new_cls,), *pick[2:])
else:
return ValueError(f"Unable to extend {o} of type {type(o)}")
# Build new type
return copy._reconstruct(o, None, *pick)
它基本上執(zhí)行以下操作:
測(cè)試對(duì)象是否已經(jīng)有一個(gè)
__dict__
. 在這種情況下,沒有什么可做的。根據(jù)提供的對(duì)象類型創(chuàng)建一個(gè)新類型。這個(gè)新類型不是槽類,盡量模仿基類。
像 中那樣減少提供的對(duì)象
copy.copy
,但僅支持__reduce_ex__(4)
簡(jiǎn)單起見。修改縮減版本以使用新創(chuàng)建的類型。
使用修改后的簡(jiǎn)化版本解開新對(duì)象。
結(jié)果為datetime
:
In [13]: d = make_extendable(datetime.datetime.now())
In [14]: d
Out[14]: datetime(2019, 3, 29, 11, 24, 23, 285875)
In [15]: d.__class__.__mro__
Out[15]: (datetime.datetime, datetime.datetime, datetime.date, object)
In [16]: d.__str__ = lambda: 'Hello, world'
In [17]: d.__str__()
Out[17]: 'Hello, world'
注意事項(xiàng)
按隨機(jī)順序:
某些類型可能不會(huì)減少。
返回的對(duì)象是一個(gè)副本,而不是初始對(duì)象。
課程不一樣,但
isinstance(d, datetime.datetime)
會(huì)是True
。類層次結(jié)構(gòu)將背叛黑客。
它可能非常慢。
__format__
有點(diǎn)特殊,因?yàn)槟枰念悓?shí)例,而不是由于格式的工作方式而綁定的方法。<在此插入您的負(fù)面評(píng)論>。
添加回答
舉報(bào)