每个访问的python列表(查找/替换内置列表)

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);

member是否等同于对象的实际引用?

是否等同于:

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变量的理解。

如注释中所述,当您循环使用诸如for member in my_list之类的列表时,member变量绑定到每个连续的列表元素。但是,在循环中重新分配该变量不会直接影响列表本身。例如,此代码不会更改列表:

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]

如果列表中包含可变对象,则可以直接修改当前的member对象:

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索引)。

当你做spam ="green"的时候,你已经把名称spam绑定到字符串对象"green"上;如果你做eggs = spam的话,你没有复制任何东西,你没有做引用指针;你只是将另一个名称eggs绑定到同一个对象上(本例中是"green")。如果你把spam和其他东西(spam = 3.14159结合起来,eggs仍然和"green"结合在一起。

当一个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

注意最后一个some_list上的[:],它导致some_list的元素发生突变(将整个事件设置为new_list的元素),而不是将名称some_list重新绑定到new_list上。这很重要吗?这要看情况!如果除了some_list之外还有其他名称绑定到同一列表对象,并且希望它们看到更新,则需要使用切片方法;如果不需要,或者不希望它们看到更新,则重新绑定--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']