Syn*_*ate 26 python foreach replace reference list
我原本以为Python是一种纯粹的传递引用语言.
来自C/C++我不禁想到内存管理,而且很难把它从我的头脑中解脱出来.因此,我试图从Java的角度来考虑它,并将所有内容都考虑在内,而不是原始内容作为参考传递.
问题:我有一个列表,其中包含一组用户定义类的实例.
如果我使用for-each语法,即:
for member in my_list:
print(member.str);
Run Code Online (Sandbox Code Playgroud)
是否member相当于对象的实际引用?
它是否相当于:
i = 0
while i < len(my_list):
print(my_list[i])
i += 1
Run Code Online (Sandbox Code Playgroud)
我认为不是,因为当我想要替换时,它不起作用,也就是说,这不起作用:
for member in my_list:
if member == some_other_obj:
member = some_other_obj
Run Code Online (Sandbox Code Playgroud)
在列表中进行简单的查找和替换.可以在for-each循环中完成,如果是,怎么做?另外,我是否只需要使用随机访问语法(方括号),或者什么都不会工作,我需要删除该条目,并插入一个新条目?即:
i = 0
for member in my_list:
if member == some_other_obj:
my_list.remove(i)
my_list.insert(i, member)
i += 1
Run Code Online (Sandbox Code Playgroud)
Gre*_*att 48
回答这个问题一直很好,因为这些评论已经改善了我对Python变量的理解.
正如评论,当你遍历的东西,如一个列表指出for member in my_list的member变量绑定到每个连续的列表元素.但是,在循环中重新分配该变量不会直接影响列表本身.例如,此代码不会更改列表:
my_list = [1,2,3]
for member in my_list:
member = 42
print my_list
Run Code Online (Sandbox Code Playgroud)
输出:
[1,2,3]
如果要更改包含不可变类型的列表,则需要执行以下操作:
my_list = [1,2,3]
for ndx, member in enumerate(my_list):
my_list[ndx] += 42
print my_list
Run Code Online (Sandbox Code Playgroud)
输出:
[43,44,45]
如果列表包含可变对象,则可以member直接修改当前对象:
class C:
def __init__(self, n):
self.num = n
def __repr__(self):
return str(self.num)
my_list = [C(i) for i in xrange(3)]
for member in my_list:
member.num += 42
print my_list
Run Code Online (Sandbox Code Playgroud)
[42,43,44]
请注意,您仍然没有更改列表,只需修改列表中的对象即可.
您可能会从阅读命名和绑定中受益.
Eth*_*man 16
Python不是Java,也不是C/C++ - 您需要停止思考如何真正利用Python的强大功能.
Python没有pass-by-value,也没有pass-by-reference,而是使用pass-by-name(或pass-by-object) - 换句话说,几乎所有东西都绑定到一个名称,然后你可以use(两个明显的例外是元组和列表索引).
执行此操作时spam = "green",您已将名称绑定spam到字符串对象"green"; 如果你那么eggs = spam你没有复制任何东西,你没有做出参考指针; 你只需将另一个名称绑定eggs到同一个对象("green"在本例中).如果你然后绑定spam到其他东西(spam = 3.14159)eggs仍将绑定"green".
当一个for循环执行时,它会获取你给它的名字,并在运行循环时依次将它绑定到iterable中的每个对象; 当你调用一个函数时,它会获取函数头中的名称并将它们绑定到传递的参数; 重新分配一个名字实际上是重新命名一个名字(它可能需要一段时间才能吸收这个 - 无论如何它都适合我).
使用for循环利用列表,有两种基本方法可以分配回列表:
for i, item in enumerate(some_list):
some_list[i] = process(item)
Run Code Online (Sandbox Code Playgroud)
要么
new_list = []
for item in some_list:
new_list.append(process(item))
some_list[:] = new_list
Run Code Online (Sandbox Code Playgroud)
注意[:]最后一个some_list- 它导致了some_list元素的变异(将整个元素设置为new_list元素),而不是将名称重新绑定some_list到new_list.这很重要吗?这取决于!如果除了some_list绑定到同一个列表对象之外还有其他名称,并且希望它们看到更新,那么您需要使用切片方法; 如果你不这样做,或者如果你不希望他们看到更新,那么重新绑定 - some_list = new_list.
你可以通过获取索引和项目来替换那里的东西.
>>> foo = ['a', 'b', 'c', 'A', 'B', 'C']
>>> for index, item in enumerate(foo):
... print(index, item)
...
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'A')
(4, 'B')
(5, 'C')
>>> for index, item in enumerate(foo):
... if item in ('a', 'A'):
... foo[index] = 'replaced!'
...
>>> foo
['replaced!', 'b', 'c', 'replaced!', 'B', 'C']
Run Code Online (Sandbox Code Playgroud)
请注意,如果要从列表中删除某些内容,则必须迭代列表的副本,否则您将收到错误,因为您正在尝试更改正在迭代的内容的大小.这可以通过切片很容易地完成.
错误:
>>> foo = ['a', 'b', 'c', 1, 2, 3]
>>> for item in foo:
... if isinstance(item, int):
... foo.remove(item)
...
>>> foo
['a', 'b', 'c', 2]
Run Code Online (Sandbox Code Playgroud)
2仍在那里因为我们在迭代它时修改了列表的大小.正确的方法是:
>>> foo = ['a', 'b', 'c', 1, 2, 3]
>>> for item in foo[:]:
... if isinstance(item, int):
... foo.remove(item)
...
>>> foo
['a', 'b', 'c']
Run Code Online (Sandbox Code Playgroud)