到处用另一个Python对象替换一个Python对象

问题描述 投票:0回答:6

如何用另一个对象替换各处的 python 对象?

我有两个班级,

SimpleObject
FancyObject
。我创建了一个
SimpleObject
,并有多个参考文献。现在我想创建一个
FancyObject
,并使所有这些引用都指向新对象。

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

a = b
不是我想要的,它只是改变了a指向的内容。我读到以下内容会起作用,但不起作用。我收到错误“属性 __dict__ 不可写”:

a.__dict__ = b.__dict__

我想要的是(伪C)的等价物:

*a = *b

我知道这很hacky,但是有什么办法可以做到这一点吗?

python python-2.7
6个回答
2
投票

没有办法。它会让你改变不可变的对象并导致各种肮脏的事情。

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?

2
投票

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

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

附注依赖猴子补丁是糟糕设计的症状


2
投票

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'))

1
投票

您有多种选择:

  1. 从一开始就使用外观模式(即主代码中的每个对象都是其他对象的代理)或单个可变容器(即每个变量都包含一个列表;您可以通过以下方式更改列表的内容)进行设计:任何此类参考)。优点是它可以与语言的执行机制一起工作,并且可以相对容易地从受影响的代码中发现。缺点:更多代码。
  2. 始终引用相同的单个变量。这是上述的一种实现。干净,没有什么花哨的,代码清晰。到目前为止我会推荐这个。
  3. 使用调试、GC 和自省功能来寻找每个符合您标准的对象并在运行时更改变量。缺点是变量的值会在代码执行期间发生变化,而无法从受影响的代码中发现。即使更改是原子的(消除一类错误),因为这可能会在执行确定值属于不同类型的代码后更改变量的类型,因此会引入在该代码中无法合理预期的错误。例如

    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.
    

更微妙的是,当区分字符串和非字符串序列时(因为字符串的定义特征是迭代它们也会产生字符串,而字符串本身是可迭代的),当展平结构时,代码可能会被破坏。

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


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

0
投票

我遇到了同样的需求,我使用这个技巧解决了它:

class Reference:

    directions = dict()

    @staticmethod
    def direct(reference): # -> Reference:
        return Reference.directions.get(reference, reference)

    @staticmethod
    def route(origin, destination) -> None:
        Reference.directions.update({origin: destination})
        return None

    def __init__(self) -> None:

        self._reference = self
        Reference.route(self, (lambda: self._reference))
        return None

    @property
    def reference(self): # -> Reference:
        return Reference.direct(self._reference)()

    @reference.setter
    def reference(self, obj) -> None:
        Reference.route(self._reference, (lambda: obj.reference))
        return None


class Example(Reference):

    def __init__(self) -> None:
        super().__init__()
        return None

满足以下条件:

obj1 = Example()
obj2 = Example()
obj3 = obj1
obj4 = Example()
print(obj1.reference == obj3.reference)
print(obj1.reference == obj2.reference)
print(obj3.reference == obj2.reference)
print()
obj1.reference = obj2.reference
print(obj1.reference == obj2.reference)
print(obj3.reference == obj2.reference)
print()
obj2.reference = obj4.reference
print(obj1.reference == obj4.reference)
print(obj2.reference == obj4.reference)
print(obj3.reference == obj4.reference)

输出:

True
False
False

True
True

True
True
True
© www.soinside.com 2019 - 2024. All rights reserved.