Python – копирование по ссылке

Есть ли возможность копировать переменную по ссылке независимо от ее экземпляра int или класса?

Моя цель состоит в том, чтобы иметь два списка одних и тех же объектов, и когда они меняются, изменение отображается во втором.

Другими словами, мне нужны указатели: /


Я просто хочу int, float и другие стандартные типы, которые обычно копируются по значению, принудительно копируют по ссылке. Это сделает мой код более последовательным.

Если такой возможности нет, оболочка класса является лучшим решением.

(отредактировано, чтобы показать пример разыменования в том же месте памяти)

Подход Luper Rouch находится на месте, когда речь идет о списках смешанных типов. Просто оберните неизменяемые типы контейнерами.

Если вы действительно настаиваете на массивах C-стиля, где элементы ограничены одним типом (массив из целых чисел, массив символов и т. Д.), Вы можете использовать модуль ctypes . Это даст вам доступ к c типам данных и указателям в дополнение к FFI для использования DLL.

 from ctypes import * containerTYPE = POINTER( c_uint ) * 10 #Array of pointers to UINTs of size 10 containerA = containerTYPE() containerB = containerTYPE() for i in range( 10 ): val = c_uint( i ) containerA[ i ] = pointer( val ) containerB[ -1 - i ] = pointer( val ) print "A\tB" for i in range( 10 ): print containerA[ i ].contents.value, "\t", containerB[ i ].contents.value for i in range( 10 ): #affects both arrays derefed = containerA[ i ].contents derefed.value = i * 2 print print "A\tB" for i in range( 10 ): print containerA[ i ].contents.value, "\t", containerB[ i ].contents.value 

Результат:

 AB 0 9 1 8 2 7 3 6 4 5 5 4 6 3 7 2 8 1 9 0 AB 0 18 2 16 4 14 6 12 8 10 10 8 12 6 14 4 16 2 18 0 

Вы можете обернуть вам неизменяемые объекты в классе:

 class MutableWrapper(object): def __init__(self, value): self.value = value a = MutableWrapper(10) b = a a.value = 20 assert b.value == 20 

Python всегда работает по ссылке, если вы явно не запрашиваете копию (фрагмент встроенного списка считается «запрашивать копию»), но срез массива numpy также работает по ссылке). Однако именно из-за этого alist=anotherlist; alist.sort() alist=anotherlist; alist.sort() означает, что отдельные объекты списка (с двумя эквивалентными именами alist и anotherlist ) сортируются – вы не можете одновременно поддерживать два разных порядка в одном и том же объекте списка.

Таким образом, в этом случае вы должны явно запросить копию (например, alist=list(anotherlist) ) – и как только вы сделали это, больше нет связи между двумя отдельными объектами списка. Вы не можете иметь его в обоих направлениях: либо вы работаете по ссылке (и имеете один объект списка и, следовательно, один заказ!), Либо вы делаете копию (в этом случае вы получаете два отдельных объекта списка).

Вы могли бы воспользоваться тем фактом, что копии, рассмотренные до сих пор, являются неглубокими – объекты (элементы), которые указаны в двух списках, являются одинаковыми … до тех пор, пока вы не выполните удаление, добавление или переназначение элементов в любом списке (с другой стороны, мутация изменяемых элементов не изменяет это соединение: это совершенно отдельная и сильно отличающаяся ситуация от любого из вышеперечисленных, поскольку в списке работают операции удаления, добавления и переназначения, вызывая метод мутации для элемента это операция над элементом – элементы не обращают внимания на любую операцию в одном или нескольких списках, ссылающихся на них, списки не обращают внимания на какую-либо операцию по одному или нескольким из элементов, на которые они ссылаются).

Существует не так много, что вы можете сделать об изъятиях и дополнениях, за исключением того, что два списка завернуты и синхронизированы в одном объекте, как это предлагается в других ответах; но для переназначения элементов, если это все, что вам нужно, вы можете превратить их в мутацию элементов, добавив один уровень косвенности – вместо того, чтобы иметь список, непосредственно ссылающийся на элементы, обратитесь к нему, например, к подписчикам с одним элементом. Например:

 >>> alist = list([x] for x in 'ciao') >>> blist = list(alist) >>> blist.sort() >>> alist [['c'], ['i'], ['a'], ['o']] >>> blist [['a'], ['c'], ['i'], ['o']] >>> blist[-1][0] = 'z' >>> blist [['a'], ['c'], ['i'], ['z']] >>> alist [['c'], ['i'], ['a'], ['z']] 

Может ли эта концепция дополнительного уровня косвенности вообще помочь с тем, что вы пытаетесь сделать, только вы можете сказать, так как мы действительно не знаем, что именно вы пытаетесь сделать ;-).

Я не уверен, какой API вы должны предоставить. Возможно, вы хотите что-то вроде

 import bisect class DualLists(object): def __init__(self, iterable=[]): self.insertion_order = list(iterable) self.sorted = sorted(self.insertion_order) def append(self, item): self.insertion_order.append(item) bisect.insort(self.sorted, item) >>> d = DualLists() >>> d.append(4) >>> d.append(6) >>> d.append(1) >>> d.insertion_order [4, 6, 1] >>> d.sorted [1, 4, 6] 

Обратите внимание, что сторонний пакетный blist обеспечивает более эффективный тип отсортированного списка, чем может обеспечить использование модуля bisect со встроенным типом list . Работа этого класса также может быть лучше обеспечена за счет использования базы данных, например, той, к которой осуществляется встроенный модуль sqlite3 .

Возможно, более элегантный, питонический способ справиться с этим, чем использовать указатели. Не могли бы вы предоставить немного больше контекста тому, что вы пытаетесь сделать.

Основываясь на том, что вы дали до сих пор, я бы подклассифицировал встроенный тип списка и сохранил его альтернативную версию. Переопределите методы списка для работы на себе и альтернативную версию, где это имеет смысл. Там, где это не имеет смысла, например, в функции sort() , определите вторую функцию для альтернативного списка.

Это действительно имеет смысл, если сорт необоснованно дорог; в противном случае я бы просто сохранил один список и сортировал по требованию.

 class MyList(list): def __init__(self, li): super(MyList, self).__init__(li) self.altlist = list(li) def append(self, x): super(MyList, self).append(x) self.altlist.append(x) def sortalt(self): ... ...