在保持其属性和功能的同时更改对象的类

时间:2016-01-19 10:29:34

标签: python python-2.7 python-internals

如果我有两个类定义如下:

class A(object):
    a = 10

class B(A):
    b = 20

如果我创建一个对象:

c = A()

然后做:

c.__class__ = B

更改('升级')对象的类,维护主类属性和方法以及获取辅助类属性和方法是否是一种有效的方法?

如果为true,这只适用于我们更改对象的类继承自前一个类的情况?最好的问候。

更新:

提供更多背景信息。 我有以下类EmbrionDevice。

class EmbrionDevice(object):
    def __init__(self, device_info, *args, **kwargs):
        super(EmbrionDevice, self).__init__(*args, **kwargs)
        # Serial number unique 64-bit address factory-set
        self.shl = device_info['source_addr_long']
        # 16-bit network address
        self.my = device_info['source_addr']
        # Node identifier
        self.ni = device_info['node_identifier']
        # Parent Address
        self.pa = device_info['parent_address']
        # Device type, 0-coordinator, 1-router, 2-End Device
        self.dt = device_info['device_type']
        # Device type identifier xbee or Digi device
        self.dd = device_info['device_type_identifier']
        # Device attributes summary in a dictionary
        self.info = device_info
        # Embrion future function
        self.function_identifier = None
        # Device state definition
        self.state = DEV_STATE_CODES['embrion']
        self.status = DEV_STATUS_CODES['no status']

我后来想要更改/升级到以下特定设备类之一:

class PassiveDevice(EmbrionDevice):
    pass

class ActiveDevice(EmbrionDevice):
    pass

基本上我想简化我的副本,避免复制所有属性。

3 个答案:

答案 0 :(得分:2)

这不是更改实例对象类的有效方法,一个简单的例子可以证明它: -

class A(object):
    a = 10
    def __init__(self):
        self.b = 20
        self.c = 30

class B(A):
    d = 35
    def __init__(self):
        self.x = 70
        self.y = 80

c = A()
c.__class__ = B

print c
  

<__main__.B object at 0x02643F10>

所以现在c是B类的实例,请尝试打印实例属性:

print c.x
print c.y

它说:

  

AttributeError: 'B' object has no attribute 'x'

答案 1 :(得分:1)

这绝对是一个黑客,这也是一个黑客攻击,但我发现它确实有点清洁:

In [1]: class A(object):
   ...:     a = 10
   ...:

In [2]: class B(A):
   ...:     b = 20
   ...:

In [3]: c = A()

In [4]: new_c = B()

In [5]: new_c.__dict__.update(c.__dict__.copy())

In [7]: repr(new_c)
Out[7]: '<__main__.B object at 0x102f32050>'

In [8]: new_c.b
Out[8]: 20

我不确定您的方法是否有效,但是,通过这种方式,您可以将旧对象的属性复制到已正确实例化的新对象中。如果您更改.__class__,则无法保证旧变量将引用正确创建的新类对象,因为__init__()__new__()等不会。跑。

要复制功能,这很难看......但是,你可以采取这样的方法:

In [18]: for name, obj in c.__class__.__dict__.iteritems():
   ....:     if hasattr(obj, '__call__'):
   ....:         # Copy the function.
   ....:
test

有各种hacky方法可以动态地向现有对象添加函数。他们都很难看,但是,他们可以找到here

答案 2 :(得分:1)

你对什么是&#34;类属性&#34;有误解?在Python中 - 所有实例属性都保存在实例本身中:它具有__dict__属性,该属性是一个字典,其中保留了由self.shl = device_info['source_addr_long']等代码定义的所有属性。 (例如,此语句在该字典上创建shl条目。

这些分配在__init__方法中运行。如果通过分配对象的__class__来更改对象的类,则它在某种意义上起作用:这是它的新类。新类可能已定义的方法现在是可访问的。但是上一课中设置的所有属性都是&#39; __init__仍然存在,因为它们是在未更改的实例__dict__上设置的。从我得到的,这可能正是你想要的 - 但请注意原始类的方法(以及类属性 - 即在类体本身上定义的属性)将是不可访问的,除非新类本身继承自原始类。如您所示的示例,这就是您正在做的事情,这种方法可能实际上适合您。

但要小心,并在交互式控制台上进行一些广泛的单元测试和测试。

替代方案可能是使用zope.interface - tis将允许您拥有一个对象,但是&#34;看起来像&#34;具有与代码的其他部分不同的属性和方法的对象,可能需要特定的接口。