用一个到处替换一个python对象

时间:2013-07-26 08:44:52

标签: python python-2.7

如何用其他对象替换任何地方的python对象?

我有两个班级,SimpleObjectFancyObject。我创建了一个SimpleObject,并且有几个引用它。现在我想创建一个FancyObject,并使所有这些引用指向新对象。

a = SimpleObject()
some_list.append(a)
b = FancyObject()

a = b不是我想要的,只是改变了指向的内容。我读过以下内容可行,但没有。我收到错误“属性__dict__不可写”:

a.__dict__ = b.__dict__

我想要的是等同于(伪-C):

*a = *b

我知道这很黑,但有没有办法实现这个目标?

5 个答案:

答案 0 :(得分:1)

没有办法。它会让你改变不可变对象并引起各种各样的肮脏。

x = 1
y = (x,)
z = {x: 3}
magic_replace(x, [1])
# x is now a list!
# The contents of y have changed, and z now has an unhashable key.

x = 1 + 1
# Is x 2, or [1, 1], or something stranger?

答案 1 :(得分:1)

您可以将该对象放在单独模块的全局命名空间中,而不是在需要时对其进行修补。

objstore.py

replaceable = object()

sample.py

import objstore

b = object()

def isB():
     return objstore.replaceable is b

if __name__ == '__main__':
     print isB()#False
     objstore.replaceable = b
     print isB()#True

P.S。依靠猴子修补是设计糟糕的症状

答案 2 :(得分:1)

PyJack有一个函数replace_all_refs,它取代了对内存中对象的所有引用。

来自文档的示例:

>>> item = (100, 'one hundred')
>>> data = {item: True, 'itemdata': item}
>>> 
>>> class Foobar(object):
...     the_item = item
... 
>>> def outer(datum):
...     def inner():
...         return ("Here is the datum:", datum,)
...     
...     return inner
... 
>>> inner = outer(item)
>>> 
>>> print item
(100, 'one hundred')
>>> print data
{'itemdata': (100, 'one hundred'), (100, 'one hundred'): True}
>>> print Foobar.the_item
(100, 'one hundred')
>>> print inner()
('Here is the datum:', (100, 'one hundred'))

调用replace_all_refs

>>> new = (101, 'one hundred and one')
>>> org_item = pyjack.replace_all_refs(item, new)
>>> 
>>> print item
(101, 'one hundred and one')
>>> print data
{'itemdata': (101, 'one hundred and one'), (101, 'one hundred and one'): True}
>>> print Foobar.the_item
(101, 'one hundred and one')
>>> print inner()
('Here is the datum:', (101, 'one hundred and one'))

答案 3 :(得分:0)

您有多种选择:

  1. 从头开始设计,使用Facade模式(即主代码中的每个对象都是其他东西的代理),或者是一个可变容器(即每个变量都包含一个列表;您可以更改内容通过任何此类参考列出)。优点是它适用于语言的执行机制,并且相对容易从受影响的代码中发现。缺点:更多代码。
  2. 始终引用相同的单个变量。这是上述的一种实现方式。清洁,没有花哨,清晰的代码。到目前为止我会推荐这个。
  3. 使用debug,gc和introspection功能搜索符合条件的每个对象,并在运行时更改变量。缺点是变量的值在代码执行期间会发生变化,而不会从受影响的代码中发现。即使更改是原子的(消除了一类错误),因为这可以在执行确定值为不同类型的代码之后更改变量的类型,从而引入在该代码中无法合理预期的错误。例如

    a = iter(b) # will blow up if not iterable
    [x for x in b] # before change, was iterable, but between two lines, b was changed to an int.
    
  4. 更巧妙地,当区分字符串和非字符串序列时(因为字符串的定义特征是迭代它们也产生字符串,它们本身是可迭代的),当展平结构时,代码可能会被破坏。

    另一个答案提及实现选项3的pyjack。尽管它可能有用,但它提到了所有问题。这可能仅适用于调试和开发。

答案 4 :(得分:0)

利用可变对象,例如列表。

a = [SimpleObject()]
some_list.append(a)
b = FancyObject()
a[0] = b

证明这是有效的:

class SimpleObject():
    def Who(self):
        print 'SimpleObject'

class FancyObject():
    def Who(self):
        print 'FancyObject'

>>> a = [SimpleObject()]
>>> a[0].Who()
SimpleObject
>>> some_list = []
>>> some_list.append(a)
>>> some_list[0][0].Who()
SimpleObject
>>> b = FancyObject()
>>> b.Who()
FancyObject
>>> a[0] = b
>>> some_list[0][0].Who()
FancyObject