更改现有对象的行为

时间:2017-03-11 22:32:11

标签: python object

我有一个程序可以生成彼此引用的对象字典。从csv文件中读取对象和引用中的数据。每次对新对象的引用被绑定时,都会生成一个新对象。根据某些属性,对象的行为可能略有不同。通过对每种行为使用不同的子类来解释行为差异的最合理的方法。

我的问题是,当在csv文件中遇到对象的第一次引用时,尚未知道所需的子类。创建临时对象直到最终类型已知并将所有属性复制到新对象将不起作用,因为这会使对象的所有现有引用无效。

我可以通过两种方式解决这个问题:

class A:
    fun(self.x):
        pass

fun1(self, x):
    print("fun1: ", x)

fun2(self, x):
    print("fun2: ", x)

a = A()
if <some condition>:
    a.fun = fun1
else:
    a.fun = fun2

在这种情况下,类和实例行为之间的关系会丢失,这在调试时可能不太好。 我的另一个解决方案一方面更优雅,但感觉就像糟糕的编程习惯:

class A:
   pass

class B(A):
    def fun(self, x):
        print("B: ", x)

class C(A):
    def fun(self, x):
        print("C: ", x)

a = A()
if <some condition>:
    a.__class__ = B
else:
    a.__class__ = C

如果认为此How dangerous is setting self.__class__ to something else?帖子中提到的对__class__赋值的大多数异议都无效。然而,它感觉不太好。

我不希望在单个类中包含所关注方法的所有变体,并根据某些数据属性调用其中一个。这将导致对象具有对它们无效的方法。

有人有另一个干净的解决方案吗?

1 个答案:

答案 0 :(得分:0)

您可以通过某些中间数据结构间接引用这些对象,例如:

objs = []

class Base(object):
    def __init__(self, name):
        self.name = name
        self.id = len(objs)
        objs.append(self)
        self._refs = []

    def link(self, obj):
        self._refs.append(obj.id)

    @property
    def refs(self):
        return [objs[r] for r in self._refs]

    @classmethod
    def replace(cls, obj):
        new_obj = cls(obj.name)
        objs[obj.id] = new_obj
        new_obj.id = obj.id
        return new_obj

    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, self.name)

class A(Base):
    pass

class B(Base):
    pass

a1 = A('a1')
a2 = A('a2')
a1.link(a2)
print(a1.refs)  # [A('a2')]
B.replace(a2)
print(a1.refs)  # [B('a2')]