[英]How can I get the reference of a List element?
是否可以从列表中获取一个元素的引用?
我知道如何将完整列表引用到另一个列表:
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中有另一个解决这个问题的方法吗?
这是不可能的,因为整数是不可变的,而列表是可变的。
在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
正如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]
Python是一种面向对象的语言,具有一流的功能。 它没有像C那样处理指针。 列表条目本身不是对象,因此您需要同时保存项目索引和对容器的引用,以执行您描述的插槽处理。 有些包执行此操作,例如缓冲区 , 内存视图或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__
,但最后规则是所有东西都是通过某个对象访问的,根源是模块词典。
在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
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
您无法将变量的引用分配给列表位置。 与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
a = b
使得名a
指的对象b
-不像在C / C ++ 它不修改到哪个对象a
前refered。
>>> a = 2
>>> id(a)
505493912
>>> a = 3
>>> id(a)
505493928
对象到a
refered没有改变; a
开始引用不同的对象。
直接这是不可能的,但是在PM 2Ring的答案中有很少的解决方法。
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
你可以做你想做的。 你原来的问题涉及整数,但你真正的问题不是。 询问有关您的实际情况的问题将获得更好的答案。
你说,
我想生成两个类列表。
我认为你的意思是对象。 然后:
一个带有用户类的“全局”列表和另一个带有文章类的列表。 每篇文章都应该有一个对本文感兴趣的“本地”用户列表。 但是,此本地列表应仅指向“全局”用户列表的用户子集。
您可以创建用户对象列表:
class User(object):
def __init__(self, name):
self.name = name
self.karma = 0
the_users = [User('Ned'), User('char0n'), User('Mithu')]
您可以列出Article对象:
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])
现在,文章的用户列表引用了用户列表中的用户对象。 如果您修改用户,则可以通过以下文章查看:
the_users[1].karma += 10
print sum(u.karma for u in the_articles[1].users)
看来你需要在需要时重新定义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]
来源:我的编程课程
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.