Python - копия ссылкой

Там возможность состоит в том, чтобы скопировать переменную ссылкой, неважно, если ее интервал или экземпляр класса?

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

Другими словами, мне нужен pointers:/


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

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

5
задан qba 6 May 2010 в 20:44
поделиться

5 ответов

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

Подход Люпера Роуча точен при работе со списками смешанных типов. Просто оберните неизменяемые типы контейнерами.

Если вы действительно настаиваете на массивах в стиле 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

Результат:

A       B
0       9
1       8
2       7
3       6
4       5
5       4
6       3
7       2
8       1
9       0

A       B
0       18
2       16
4       14
6       12
8       10
10      8
12      6
14      4
16      2
18      0
0
ответ дан 18 December 2019 в 10:42
поделиться

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

class MutableWrapper(object):

    def __init__(self, value):
        self.value = value

a = MutableWrapper(10)
b = a
a.value = 20
assert b.value == 20
8
ответ дан 18 December 2019 в 10:42
поделиться

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

Основываясь на том, что вы дали на данный момент, я бы подклассифицировал встроенный тип списка и заставил его хранить альтернативную версию самого себя. Переопределите методы списка для работы с самим собой и альтернативной версией себя, где это имеет смысл. Там, где это не имеет смысла, например, в функции 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):
        ...

    ...
0
ответ дан 18 December 2019 в 10:42
поделиться

Python всегда работает по ссылке, если вы явно не запрашиваете копию (считается, что часть встроенного списка «запрашивает копию» - но часть массива numpy также работает по ссылке). Однако именно поэтому 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']]

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

8
ответ дан 18 December 2019 в 10:42
поделиться

Я не уверен, какой 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.

0
ответ дан 18 December 2019 в 10:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: