Python - 通过引用复制

时间:2010-05-06 18:33:14

标签: python reference

是否有可能通过引用复制变量,无论其int或类实例是什么?

我的目标是拥有两个相同对象的列表,当一个更改时,更改在第二个中可见。

换句话说,我需要指针:/


我只想要int,float和其他通常按值复制的标准类型,强制通过引用复制。这将使我的代码更加一致。

如果没有这种可能性,类包装器是最好的解决方案。

5 个答案:

答案 0 :(得分:8)

您可以将不可变对象包装在类中:

class MutableWrapper(object):

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

a = MutableWrapper(10)
b = a
a.value = 20
assert b.value == 20

答案 1 :(得分:8)

Python总是通过引用工作,除非你明确要求一个副本(一个内置列表的片段被认为是“要求复制” - 但是一块numpy数组也可以通过引用工作)。但是,正因为如此,alist=anotherlist; alist.sort()表示单个列表对象(具有两个等效名称alistanotherlist)被排序 - 您无法同时维护两个不同的排序在同一个列表对象上。

所以,在这种情况下,你必须明确要求一个副本(例如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']]

这个额外间接层次的概念是否可以对你正在尝试做的事情有所帮助,只有你能说出来,因为我们并不真正知道你是什么< strong> 尝试做; - )。

答案 2 :(得分:0)

我不确定您必须提供什么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模块访问的数据库)也可以更好地处理此类的操作。

答案 3 :(得分:0)

与使用指针相比,可能有一种更优雅,更pythonic的方式来处理它。你能否提供更多关于你想要做的事情的背景。

根据你到目前为止所给出的内容,我将继承内置列表类型并让它存储自己的替代版本。覆盖列表方法以对其自身进行操作,并在其有意义的情况下替换自身的替代版本。如果它没有意义,就像在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):
        ...

    ...

答案 4 :(得分:0)

(已编辑以显示取消引用相同内存位置的示例)

在处理混合类型列表时,Luper Rouch的方法很有用。只需用容器包装不可变类型。

如果你真的坚持C风格的数组,其元素被限制为单一类型(整数数组,字符数组等),你可以使用ctypes模块。除了FFI之外,它还允许您访问c数据类型和指针以使用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