Python List & for-each access (Find/Replace in built-in list)
我最初认为python是一种纯粹的旁路参考语言。
来自C/C++的我不禁想起了内存管理,很难把它忘掉。所以我试着从Java的角度来思考它,把所有的东西都当作是通过引用。
问题:我有一个列表,其中包含一个用户定义类的一组实例。
如果我使用for each语法,即:
1 2 | for member in my_list: print(member.str); |
是否等同于:
1 2 3 4 | i = 0 while i < len(my_list): print(my_list[i]) i += 1 |
我认为不是,因为当我想做一个替换时,它不起作用,也就是说,这不起作用:
1 2 3 | for member in my_list: if member == some_other_obj: member = some_other_obj |
列表中的简单查找和替换。如果可以,如何在for-each循环中完成?否则,我是否只需要使用随机访问语法(方括号),或者两者都不起作用,我需要删除条目并插入一个新的条目?即。:
1 2 3 4 5 6 | i = 0 for member in my_list: if member == some_other_obj: my_list.remove(i) my_list.insert(i, member) i += 1 |
回答这个问题是很好的,因为这些评论提高了我对Python变量的理解。
如注释中所述,当您循环使用诸如
1 2 3 4 | my_list = [1,2,3] for member in my_list: member = 42 print my_list |
输出:
[1, 2, 3]
如果要更改包含不可变类型的列表,需要执行以下操作:
1 2 3 4 | my_list = [1,2,3] for ndx, member in enumerate(my_list): my_list[ndx] += 42 print my_list |
输出:
[43, 44, 45]
如果列表中包含可变对象,则可以直接修改当前的
1 2 3 4 5 6 7 8 9 10 | 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 |
[42, 43, 44]
请注意,您仍然没有更改列表,只需修改列表中的对象即可。
您可能会从阅读命名和绑定中受益。
Python不是Java,也不是C/C++——你需要停止使用这种方法来真正地利用Python的能力。
python没有pass-by值,也没有pass-by引用,而是使用pass-by-name(或pass-by-object)——换句话说,几乎所有内容都绑定到一个可以使用的名称(两个明显的异常是tuple和list索引)。
当你做
当一个for循环执行时,它使用你给它的名称,并在运行循环时将它依次绑定到iterable中的每个对象;当你调用一个函数时,它使用函数头中的名称,并将它们绑定到传递的参数;重新分配一个名称实际上是重新绑定一个名称(它可能需要一段时间来吸收这个名称——对我来说是这样的,anywaY)。
对于使用列表的循环,有两种基本方法可以分配回列表:
1 2 | for i, item in enumerate(some_list): some_list[i] = process(item) |
或
1 2 3 4 | new_list = [] for item in some_list: new_list.append(process(item)) some_list[:] = new_list |
注意最后一个
您可以通过获取索引和项目来替换其中的内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> 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'] |
请注意,如果要从列表中删除某些内容,则必须对列表的副本进行迭代,否则将出现错误,因为您试图更改正在迭代的内容的大小。这可以很容易地用切片完成。
错误:
1 2 3 4 5 6 7 | >>> foo = ['a', 'b', 'c', 1, 2, 3] >>> for item in foo: ... if isinstance(item, int): ... foo.remove(item) ... >>> foo ['a', 'b', 'c', 2] |
2仍然在其中,因为我们在遍历它时修改了列表的大小。正确的方法是:
1 2 3 4 5 6 7 | >>> foo = ['a', 'b', 'c', 1, 2, 3] >>> for item in foo[:]: ... if isinstance(item, int): ... foo.remove(item) ... >>> foo ['a', 'b', 'c'] |