Python:是否有用于更改实例类的用例?

时间:2013-04-06 20:45:22

标签: python object

相关:Python object conversion

我最近了解到Python允许您像这样更改实例的类:

class Robe:
    pass

class Dress:
    pass

r = Robe()
r.__class__ = Dress

我试图弄清楚是否存在“转化'像这样的对象可能很有用。我在IDLE中搞砸了这一点,我注意到的一件事就是分配一个不同的类并没有调用新类的__init__方法,尽管这可以如果需要,可以明确地完成。

几乎我能想到的每个用例都可以通过编写更好地服务,但我是一个编码newb所以我知道什么。 ;)

2 个答案:

答案 0 :(得分:6)

对于不相关的类,很少有充分的理由这样做,例如您的示例中的RobeDress。如果没有一点工作,很难确保你最终获得的对象处于一个理智的状态。

但是,如果要使用非标准工厂函数或构造函数来构建基础对象,则从基类继承时可能很有用。这是一个例子:

class Base(object):
    pass

def base_factory():
    return Base()  # in real code, this would probably be something opaque

def Derived(Base):
    def __new__(cls):
        self = base_factory()     # get an instance of Base
        self.__class__ = Derived  # and turn it into an instance of Derived
        return self

在此示例中,Derived类的__new__方法想要使用base_factory方法构造其对象,该方法返回Base类的实例。通常这种工厂位于某个库中,你无法确定它是如何形成对象的(你不能自己调用​​Base()super(Derived, cls).__new__(cls)来获得相同的结果)。

重写实例的__class__属性,以便调用Derived.__new__的结果将成为Derived类的实例,从而确保它具有Derived.__init__方法呼吁它(如果存在这样的方法)。

答案 1 :(得分:2)

我记得很久以前使用这种技术在识别出它们所拥有的数据类型之后“升级”现有对象。它是实验性XMPP客户端的一部分。 XMPP使用许多简短的XML消息(“节”)进行通信。

当应用程序收到一个节时,它被解析为一个DOM树。然后应用程序需要识别它是什么类型的节(存在节,消息,自动查询等)。例如,如果它被识别为消息节,则DOM对象被“升级”为提供诸如“get_author”,“get_body”等方法的子类。

我当然可以创建一个新类来表示已解析的消息,创建该类的新对象并从原始XML DOM对象复制相关数据。但是,就地改变对象的类有两个好处。首先,XMPP是一个非常可扩展的标准,如果代码的其他部分在那里找到了有用的东西,或者在调试时,仍然可以轻松访问原始的DOM对象。其次,对代码进行概要分析告诉我,创建一个新对象并显式复制数据比仅仅重用那些很快会被快速销毁的对象要慢得多 - 这种差异在XMPP中很重要,XMPP使用了许多短消息。

我不认为这些原因中的任何一个都不能证明在生产代码中使用这种技术,除非你真的需要CPython中的(不是那么大)加速。这只是一个黑客,我发现在实验应用程序中使代码更短更快。另请注意,此技术很容易在非CPython实现中破坏JIT引擎,使代码更慢!