是否可以从列表中获取一个元素的引用?
我知道如何将完整列表引用到另一个列表:
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中有另一种解决这个问题的方法吗?
答案 0 :(得分: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
答案 1 :(得分: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]
答案 2 :(得分: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__
等特定方法,但在结束规则是通过一些对象访问所有内容,其中根是模块字典。
答案 3 :(得分:1)
在Python中,一切都是对象,包括数字。数字是不可变的对象,它们只存在一次。换句话说,在上面的例子中,a
不保持值为2,它保存对表示整数2的Number
对象的引用。这可以很容易地验证:
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]
的当前值?我想到了两个选择:
存储元素的索引,而不是其值:
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
在列表中,存储对象并更改这些对象的值:
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
答案 4 :(得分: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
答案 5 :(得分:0)
a = b
使名称a
引用对象b
- 与C / C ++ 不同,它不会修改a
之前提到的对象
>>> 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
答案 6 :(得分:-1)
你可以做你想做的事。你的原始问题涉及整数,但你真正的问题并不是。询问有关您真实情况的问题将获得更好的答案。
你说,
我想生成两个类列表。
我认为你的意思是对象。然后:
One&#34; global&#34;带有用户类的列表和带有文章类的另一个列表。每篇文章都应该有一个&#34; local&#34;对本文感兴趣的用户列表。但是这个本地列表应该只指向&#34; global&#34;的用户子集。用户列表。
您可以列出用户对象:
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])
现在文章&#39;用户列表引用用户列表中的用户对象。如果您修改用户,则可以通过以下文章查看:
the_users[1].karma += 10
print sum(u.karma for u in the_articles[1].users)
答案 7 :(得分:-4)
似乎你需要在需要时重新定义b = a [1],或使用[1]。如上所述,与列表不同,整数是不可变的 - 我不会重申其他人所说的 - 因此不会起作用。我建议只在需要时使用[1],或者为了长线的可读性重新分配b = a [1]。
由于我的误解,回答错误的任务:
您可以在定义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]
来源:我的编程课程