为了账号安全,请及时绑定邮箱和手机立即绑定

将插槽对象复制到非插槽中

将插槽对象复制到非插槽中

慕的地6264312 2021-12-21 16:56:21
一些 Python 标准类是插槽,例如datetime.datetime. 这不是我可以改变的,很多图书馆都期望datetimeobject.我想更改__format__现有datetime对象的默认方法,但不幸的是,由于这是一个插槽类,因此被禁止:In [10]: import datetimeIn [11]: datetime.datetime.now().__format__ = lambda s, f: ''---------------------------------------------------------------------------AttributeError                            Traceback (most recent call last)<ipython-input-11-c98141136d9d> in <module>()----> 1 datetime.datetime.now().__format__ = lambda s, f: ''AttributeError: 'datetime.datetime' object attribute '__format__' is read-only是否有可能滥用 python 的动态特性来实现这一点?大概吧。
查看完整描述

1 回答

?
慕婉清6462132

TA贡献1804条经验 获得超2个赞

这是我的解决方案:


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)

它基本上执行以下操作:

  1. 测试对象是否已经有一个__dict__. 在这种情况下,没有什么可做的。

  2. 根据提供的对象类型创建一个新类型。这个新类型不是槽类,尽量模仿基类。

  3. 像 中那样减少提供的对象copy.copy,但仅支持__reduce_ex__(4)简单起见。

  4. 修改缩减版本以使用新创建的类型。

  5. 使用修改后的简化版本解开新对象。

结果为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'

注意事项

按随机顺序:

  • 某些类型可能不会减少。

  • 返回的对象是一个副本,而不是初始对象。

  • 课程不一样,但isinstance(d, datetime.datetime)会是True

  • 类层次结构将背叛黑客。

  • 它可能非常慢。

  • __format__有点特殊,因为您需要更改类实例,而不是由于格式的工作方式而绑定的方法。

  • <在此插入您的负面评论>。


查看完整回答
反对 回复 2021-12-21
  • 1 回答
  • 0 关注
  • 182 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号