2013-07-26 2 views
3

Как заменить объект python на другой объект?Заменить один объект python другим во всем мире

У меня есть два класса, SimpleObject и FancyObject. Я создал SimpleObject и имею несколько ссылок на него. Теперь я хотел бы создать FancyObject и сделать все эти ссылки на новый объект.

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

a = b не то, что я хочу, это просто меняет то, что а указывает. Я читал, что следующее будет работать, но нет. Я получаю сообщение об ошибке «Атрибут __dict__ не доступен для записи»:

a.__dict__ = b.__dict__ 

То, что я хочу, это эквивалент (псевдо-C):

*a = *b 

Я знаю, что это Hacky, но есть ли способ для этого?

+0

Итак, вы хотите, чтобы изменить то, что данные хранятся в том месте, где 'a' хранится? Я отправлю ответ после обеда .. – pradyunsg

+0

@Schoolboy Да. В принципе, я поставил простой объект в a и хотел (лениво) продвинуть его к более сложному объекту b, когда возникнет такая необходимость. a и b имеют один и тот же интерфейс, поэтому код, использующий их, должен иметь возможность справиться с этим. – jdm

ответ

0

Невозможно. Это позволит вам мутировать неизменные объекты и вызывать всевозможные гадости.

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? 
+0

Ну, содержимое 'y',' z' не изменится, поскольку они относятся к тому, что 'x' ссылалось на ранее. Единственное, что изменилось, это то, что означает' x'. (Исправьте меня, если я ошибаюсь, поскольку я не знаю C). – pradyunsg

+1

Если вы хотите изменить то, что означает имя 'x',' x = whatever' - это то, что вам нужно. Если вы хотите магически заменить объект 'x', ссылаясь на новый объект, это должно быть видимым везде, где использовался старый объект, включая dicts и кортежи. – user2357112

+0

@Schoolboy, но это то, о чем попросил OP: заменить не только 'x', но и все другие имена, ссылающиеся на один и тот же объект. Если вы не поняли, что в Python '1' есть объект и в основной реализации Python все, используя значение' 1', просто ссылаются на один и тот же объект. – Duncan

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. Полагаться на исправление обезьяны является симптомом плохого дизайна

1

Я только что нашел this. Его функция replace_all_refs работает очень хорошо.

+2

Вы должны включить в свое сообщение немного больше информации о том, к чему вы привязываетесь. – Michelle

0

У вас есть несколько вариантов:

  1. Design это с самого начала, используя шаблон Фасад (т.е. каждый объект в основной код прокси-сервер для чего-то другого), или один изменяемый контейнер (т.е. каждая переменная содержит список, вы можете изменить содержимое списка через любую такую ​​ссылку). Преимущества заключаются в том, что он работает с машиной исполнения на языке, и относительно легко обнаруживается из затронутого кода. Нижняя сторона: больше кода.
  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. 
    

Более тонко, когда различие между строками и нестроковыми последовательностями (потому что отличительная чертой строк является то, что итерация их также дает строку, которые само по себе являются итерацией), при выпрямлении структуры, код может быть сломан.

В другом ответе упоминается 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 
Смежные вопросы