2014-11-14 81 views
4

是否有可能从列表中获取一个元素的引用?如何获取List元素的引用?

我知道如何引用的完整列表到另一个列表:

a = [1,2,3] 
b = [] 

b = a 

a[1] = 3 

print (b) #b is now [1, 3, 3] 

但我怎么能得到参考一个元素? 例如:

a = [1,2,3] 
b = [] 

b = a[1] 

a[1] = 3 

print (b) #b is now 2, but I want the value 3 like it is in a[1] 

或者是有在python这个问题的另一个解决方案?

+1

不,您所描述的行为是不可能在Python。 – CoryKramer 2014-11-14 13:11:45

+0

好的。对于两个指向相同值的列表,是否没有其他possility?但是一个列表只是另一个列表的一个子集。 – char0n 2014-11-14 13:17:39

+0

只有列表中的值是可变的。 – jonrsharpe 2014-11-14 13:19:24

回答

3

这是不可能的,因为整数是不可变的,而列表是可变的。

b = a[1]你实际上是赋予了新的价值b

演示:

>>> a = 2 
>>> id(a) 
38666560 
>>> a += 2 
>>> id(a) 
38666512 

您可以像现在这样,

>>> a = [1,2,3] 
>>> b = a 
>>> a[1] = 3 
>>> b 
[1, 3, 3] 
>>> a 
[1, 3, 3] 
>>> id(a) 
140554771954576 
>>> id(b) 
140554771954576 

You can read this document.

+0

好吧,我从来没有听说过有关“可变”和“不可变”的内容。整数值仅仅是我的问题的一个例子,指向列表中的元素,还是我遇到了与其他类型相同的问题?因为实际上我想列出类并将其他列表指向此“类”列表的特定元素。 – char0n 2014-11-14 13:45:32

+5

如果你从来没有听说过“可变”和“不可变”,那么你对Python变量的工作方式有一个很大的缺陷。我建议你看看Ned Batchelder的[关于Python名称和值的事实和神话](http://nedbatchelder.com/text/names.html)(Ned在这里是常用的)。 – 2014-11-14 13:53:48

+0

@ PM2Ring它非常有用 – 2014-11-14 13:54:54

-4

好像你需要只需在需要时重新定义b = a [1]或使用[1]。如上所述,整数是不变的,不像列表 - 我不会重申其他人说的 - 所以不起作用。我建议只在需要的地方使用[1],或者为了长行的可读性而重新指定b = a [1]。

回答以下错误questin由于我的误解:

您可以定义b当使用*操作。

a = [1,2,3] 
b = 1*a #my book says *a will work, but it creates an error in spyder when I tested it 

b 
>>> [1,2,3] 

a[1] = 3 

a 
>>> [1,3,3] 

b 
>>> [1,2,3] 

来源:我的编程过程

+0

这是代码不起作用,不回答问题。 – Matthias 2014-11-14 13:33:15

+0

我不明白这对我有何帮助。 在结尾b只包含a的值。 – char0n 2014-11-14 13:40:10

+0

代码确实有用,我在发布@Matthias之前对其进行了测试。不过,我很抱歉,因为我可能误解了这个问题并且错误地回答了它。 – Matthew 2014-11-15 14:48:30

0

你不能从一个变量的引用分配到列表中的位置。与C++不同,在Python中这是不可能的。你可以去最近的是创建一个匿名函数来引用单一列表索引,并分配一个新的值给它:

>>> L = [1,2,3] 
>>> def itemsetter(L, pos): 
...  def inner(x): 
...    L[pos] = x 
...  return inner 
... 
>>> f = itemsetter(L, 1) 
>>> f 
<function inner at 0x7f9e11fa35f0> 
>>> f(9) 
>>> L 
[1, 9, 3] 

此功能类似于方式STDLIB功能operator.attrgetter作品。

另一个最接近的方法是将列表中的每个元素作为可引用的可变对象进行包装。例如:

>>> L = [1,2,3] 
>>> L2 = [[x] for x in L] 
>>> L2 
[[1], [2], [3]] 
>>> A = L2[1] 
>>> A[0] = 9 
>>> L2 
[[1], [9], [3]] 

而不是列表,您可以创建自定义类:

>>> class wrap: 
...  def __init__(self, value): 
...    self.value = value 
... 
>>> L3 = [wrap(x) for x in L] 
>>> L3 
[<__main__.wrap instance at 0x7feca2c92ab8>, <__main__.wrap instance at 0x7feca2c92b00>, <__main__.wrap instance at 0x7feca2c92b48>] 
>>> A = L3[1] 
>>> A.value = 9 
>>> L3[1].value 
9 
>>> L3[0].value 
1 
>>> L3[2].value 
3 
+0

我想这可能会帮助我。但我希望在没有任何解决方法的情况下获得解决方案。 – char0n 2014-11-14 13:48:40

+0

@ char0n另一个解决方法是用一些可引用的对象来包装列表中的每个元素。即,L = [1,2,3]; L2 = [[1],[2],[3]]; A = L2 [1]; A [0] = 9; L2 == [[1],[9],[3]] – vz0 2014-11-14 13:56:22

+0

我认为这是我需要的。 :-) – char0n 2014-11-14 15:47:58

1

正如jonrsharpe说,你可以通过在列表中使用可变元素做你想要什么,例如使列表元素自己列出。

例如

a = [[i] for i in xrange(5)] 
print a 

b = a[3] 
print b[0] 


a[3][0] = 42 

print a 
print b[0] 


b[:] = [23] 

print a 
print b 

输出

[[0], [1], [2], [3], [4]] 
3 
[[0], [1], [2], [42], [4]] 
42 
[[0], [1], [2], [23], [4]] 
[23] 
1

Python是与第一类功能的面向对象的语言。它不像C那样处理指针。列表条目本身不是对象,因此您需要同时持有一个项索引和一个对容器的引用,以执行您描述的那种插槽处理。有这样做的软件包,例如buffers,memory views或numpy ndarrays,但它需要一个间接层,因为foo = something表单的分配将绑定名称foo,而不是修改foo用于引用的内容。

这里就是这样一个间接类的一个实例:

class Indirect(object): 
    def __init__(self, container, item): 
     self.container = container 
     self.item = item 
    @property 
    def value(self): 
     return self.container[self.item] 
    @value.setter 
    def value(self, value): 
     self.container[self.item] = value 

l = [1,2,3] 
ref = Indirect(l, 1) 
ref.value = 5 
print(l) 

第一类功能支持意味着您也可以动态创建一个功能您需要的具体任务:

l = [1,2,3] 
def callwith5(func): # doesn't know what func does 
    return func(5) 
setanitem = lambda i: l[1]=i # creates a new function 
callwith5(setanitem) 
print(l) 

表达这种差异的另一种方式是Python在C术语中并不真正拥有lvalue;我们只是有一个赋值语句翻译成不同的调用几个语法扩展:

a = 1  # if a is global: setitem(globals(), 'a', 1) 
a = 1  # otherwise:  setitem(locals(), 'a', 1) 
foo.a = 1 # setattr(foo, 'a', 1) => foo.__setattr__('a', 1) 
l[1] = 5 # setitem(l, 1, 5)  => l.__setitem__(1, 5) 

他们中许多人进行了优化,使得没有setitem,SETATTR等的查询,而这些又将有一组规则引用到具体的方法如__setitem____setattr__,但最终规则是所有东西都是通过某个对象访问的,其根是模块字典。

1

在Python中,一切都是一个对象,包括数字。数字是不可变的对象,它们只存在一次。在上面的例子中换句话说,a确实保持值的两个,它保持所述参照Number对象,表示整数2。这可以很容易地进行验证:

a = 2 # reference to the object that represents integer 2 
print type(2), type(a), isinstance(2, Number), isinstance(a, Number) 
=> <type 'int'> <type 'int'> True True 

类似地,这是通过示出看物色对象,这是由id函数返回的:

a = 2 
print id(2), id(a) 
=> 4301263008 4301263008 

我们现在可以回答你的问题:

但我怎样才能得到一个元素的参考?

您已经获得参考元素:

a = [1,2,3] 
b = [] 
b = a[1] 
a[1] = 3 
print (b) #b is now 2, but I want the value 3 like it is in a[1] 
=> 2 
print id(a[1]), id(b), id(2) 
=> 4301262984 4301263008 4301263008 

Python列表始终存储对象的引用。通过设置a[1] = 3,您实际上正在改变第二个列表元素从id(2)引用到id(3)的内容。 b继续(正确)持有对象id(2)的引用,这是您要求它执行的操作。

有没有办法达到你想要的,即有b莫名其妙地指向a[1]的当前值?两个选项映入脑海:

  1. Store中元素的索引,而不是它的价值:

    a = [1,2,3] 
    b = [] 
    b = a # reference the list 
    b_i = 1 # reference the index 
    a[1] = 3 # change value at index 1 
    print (b[b_i]) 
    => 3 
    a[1] = 4 
    print (b[b_i]) 
    => 4 
    
  2. 在列表中,存储对象和改变这些对象的值:

    class Element(int): 
        def __init__(self, value): 
         self.value = value 
        def __str__(self): 
         return "%s" % self.value 
        def __repr__(self): 
         return "%s" % self.value 
    a = [Element(n) for n in [1,2,3]] 
    print a 
    => [1, 2, 3] 
    b = a[1] 
    a[1].value = 3 # don't change a[1]'s reference, change its value! 
    print (b) 
    => 3 
    print id(a[1]), id(b) # same object 
    => 4372145648 4372145648 
    
-1

你可以做你想做的。你的原始问题涉及整数,但你真正的问题不是。询问你的真实情况会得到更好的答案。

你说,

我要生成的类两个列表。

我认为你的意思是对象。然后:

一个“全局”列表与用户类和另一个列表与文章类。每篇文章应该有一个“本地”用户列表,对本文感兴趣。但是这个本地列表应该只指向“全局”用户列表的一部分用户。

可以使用户对象的列表:

class User(object): 
    def __init__(self, name): 
     self.name = name 
     self.karma = 0 

the_users = [User('Ned'), User('char0n'), User('Mithu')] 

可以使文章对象的列表:

class Article(object): 
    def __init__(self, title): 
     self.title = title 
     self.users = [] 

the_articles = [Article("How to cook"), Article("Latest News")] 

你可以用文章的用户联系起来:

the_articles[0].users.append(the_users[0]) 
the_articles[1].users.append(the_users[0]) 
the_articles[1].users.append(the_users[1]) 

现在文章的用户列表引用了您的User对象用户列表。如果修改用户,它通过文章的可见:

the_users[1].karma += 10 
print sum(u.karma for u in the_articles[1].users) 
0

a = b使得名a指的对象b - 不像在C/C++ 它不会修改到a之前refered对象。

>>> a = 2 
>>> id(a) 
505493912 
>>> a = 3 
>>> id(a) 
505493928 

a引用的对象没有改变; a开始引用不同的对象。

直接这是不可能的,但有几个解决方法,像这样在PM 2Ring's answer

另一个解决方法:

def overload(*functions): 
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs) 

class Ref: 
    def __init__(self, new_target): 
     self.target=new_target 
    def __repr__(self): 
     return 'Ref(' + repr(self.target) + ')' 
    __call__=overload(None, lambda self: self.target, __init__) 

#用法:

>>> a = [Ref(1), Ref(2), Ref(3)] 
>>> b = a[1] 
>>> print(b) 
Ref(2) 
>>> a[1](3) 
>>> print(b) 
Ref(3) 
>>> print(b()) 
3