Reputation: 79
alist = ['1', '2', '3']
blist = alist[:]
for x in alist:
if not "@gmail.com" in alist:
x = x + "@gmail.com"
for x in range(len(blist)):
if not "@gmail.com" in blist[x]:
blist[x] = blist[x] + "@gmail.com"
The first block of code does not implement what I need, yet the second one does.
What is the difference between these two blocks of code?
Upvotes: 2
Views: 63
Reputation: 104032
Your fist loop can be fixed to be:
for i, x in enumerate(alist):
if "@gmail.com" not in x:
alist[i] = x + "@gmail.com"
Or, more succinctly:
email="@gmail.com"
alist=[x+email if email not in x else x for x in alist]
Since in
will return true if that string is anywhere in the string, not x.endswith("@gmail.com")
is preferred in both cases above.
Upvotes: 1
Reputation: 22041
Shorty: In first sample you aren't mutating list values, in second example you do.
In first loop you modifying x
, which actually is copy of list item, but not that item, in second sample you modifying item of list by accessing it by index. See Immutable vs Mutable types to get more info regarding mutable and immutable types
However if you would apply loops on list which contain mutable types, the items would be modified by both for
loops:
alist = [['1'], ['2'], ['3']]
blist = [['1'], ['2'], ['3']]
for x in alist:
x.append("@gmail.com")
print alist
for x in range(len(blist)):
blist[x].append("@gmail.com")
print blist
Upvotes: 2
Reputation: 104762
When you do x = x + "@gmail.com"
in the first version of the code, you're creating a new value and rebinding the name x
to refer to it. This has no effect on alist
, even though that's where the previous x
value came from.
When you do blist[x] = blist[x] + "@gmail.com"
on the other hand, you're explicitly modifying the list. You're rebinding blist[x]
to refer to a new value.
Note that with different list contents, you might have been able to make the first version of the code work, using "in place" modification. Strings are immutable though, so there are no in-place operations. However, if alist
contained mutable items such as list
s, code like x += ["foo"]
would extend the inner list in place. The +=
operator will attempt to do an in place addition if the type of the object supports it (by having an __iadd__
method). For types that don't support inplace operations though, it's just the same as x = x + y
, which will have the same issue you've encountered.
Upvotes: 2
Reputation: 59315
Because strings are immutable:
https://docs.python.org/2/reference/datamodel.html
Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable. (The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle.) An object’s mutability is determined by its type; for instance, numbers, strings and tuples are immutable, while dictionaries and lists are mutable.
In the first example, you are creating a new variable named x
each time you concatenate additional values to it.
I the second example, however, you are simply changing the value at the same index of your list
.
Upvotes: 0