2014-11-14 83 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