This question already has answers here:
Understanding slicing
(38 answers)
Closed 8 years ago.
sentence = "Hello"
print sentence
print sentence[:]
Both outputs the same thing, i.e. Hello
So, when and why to use/not use [:] ?
Thanks! :)
As Nobi pointed out in the comments, there's already a question regarding Python's slicing notation. As stated in the answer to that question, the slicing without start and end values ([:]) basically creates a copy of the original sequence.
However, you have hit a special case with strings. Since strings are immutable, it makes no sense to create a copy of a string. Since you won't be able to modify any instance of the string, there's no need to have more than one in memory. So, basically, with s[:] (being s a string) you're not creating a copy of the string; that statement is returning the very same string referenced by s. An easy way to see this is by using the id() (object identity) function:
>>> l1 = [1, 2, 3]
>>> l2 = l1[:]
>>> id(l1)
3075103852L
>>> id(l2)
3072580172L
Identities are different. However, with strings:
>>> s1 = "Hello"
>>> s2 = s1[:]
>>> id(s1)
3072585984L
>>> id(s2)
3072585984L
Identity is the same, meaning both are the same exact object.
>>> a = [1, 2, 3]
>>> b=a[:]
>>> id(b)
4387312200
>>> id(a)
4387379464
When you want to make a deep copy of an array.
>>> a='123'
>>> b=a[:]
>>> id(a)
4387372528
>>> id(b)
4387372528
But since string is immutable, string[:] has no difference with string itself.
P.S. I see most of people answering this question didn't understand what is the question at all.
Thee reason why you are getting Hello as output, is you are not passing any parameter.
L[start:stop:step]
Here L is your variable, which holds Hello. and start means the initial position of the string and stop means where you want to end your string with & step means how many char you want to skip.
For more information on this topic, visit this
See, if that resolved your issue.
Related
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 2 years ago.
This one is making me absolutely crazy, so any help would be much appreciated. I have a program where I'm iterating through a list in a function. Here's a toy model of the problem:
masterList = ["person","woman","man","camera","television"]
workingList = masterList
def removeItem (workingList):
item = workingList.pop(2)
print("Test 1:",workingList)
removeItem(workingList)
print("Test 2:", workingList)
print("Test 3:", masterList)
As expected, "Test 1" prints out the list with an item removed.
However, "Test 2" also prints out the list with an item removed. I wasn't expecting that, but no matter. That's not the real problem, but I'm sure there's something I don't understand here about variable scopes and variable shadowing.
No the real problem is "Test 3", which as you can see, is printing out the masterList, which shouldn't even be touched by the removeItem function or the pop function within it. And yet, it too is printing out the list with an item removed.
How can this be happening, and how can I prevent it?
Thanks so much!
Cheers,
Ari
Python lists are mutable objects.
m = list([1, 2, 3])
n = m
a = 5
b = a
id(a) == id(b)
# id() return "identity" of the object.
# True, Both a and b are references to the same object.
id(m) == id(n)
# True, Both m and n are references to the same object.
b = b + 2
id(a) == id(b)
# False, a new object on separate location is created, which b will point.
n.pop()
id(m) == id(n)
# True, the object is mutated, and m and n still references to the same object.
Since, python lists are mutable, m and n will still be reference to the same object after mutation. Whereas, for immutable objects like int, a new object will be created and the identifier will refer to the new object.
Gist is, in your scenario, there has been only one object since python lists are mutable.
However, if you need the original list unchanged when the new list is modified, you can use the copy() method.
new_list = original_list.copy()
The ids of new_list and original_list is different.
Learn here about mutability in detail: https://medium.com/#meghamohan/mutable-and-immutable-side-of-python-c2145cf72747.
You have to make a copy of the masterList, otherwise workingList is nothing more than a reference.
If your list does not contain other containers (which yours doesn't), then a shallow copy is sufficient. There are numerous ways to make a shallow copy but slicing is the most optimal.
masterList = ["person","woman","man","camera","television"]
workingList = masterList[:] #copy via slice
a bunch of other ways to make a shallow copy
workingList = masterList * 1
workingList = masterList.copy()
workingList = list(masterList)
workingList = [*masterList]
import copy
workingList = copy.copy(masterList)
If you have a list that does possess something that holds a reference (like other containers, classes, etc), then you need to make a deepcopy.
import copy
a = [[1, 2, 3], ['a', 'b', 'c']]
b = copy.deepcopy(a)
Looks like I figured it out. The two lists are actually the same list unless you use list.copy()
So replacing the top two lines with:
masterList = ["person","woman","man","camera","television"]
workingList = masterList.copy()
makes everything perform as expected! Well, I still can't say I understand how the variable scopes work in their entirety, but at least this solves the major problem.
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 4 years ago.
When I ran this script (Python v2.6):
a = [1,2]
b = a
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2,3]
I expected print b to output [1,2]. Why did b get changed when all I did was change a? Is b permanently tied to a? If so, can I make them independent? How?
Memory management in Python involves a private heap memory location containing all Python objects and data structures.
Python's runtime only deals in references to objects (which all live in the heap): what goes on Python's stack are always references to values that live elsewhere.
>>> a = [1, 2]
>>> b = a
>>> a.append(3)
Here we can clearly see that the variable b is bound to the same object as a.
You can use the is operator to tests if two objects are physically the same, that means if they have the same address in memory. This can also be tested also using the id() function.
>>> a is b
>>> True
>>> id(a) == id(b)
>>> True
So, in this case, you must explicitly ask for a copy.
Once you've done that, there will be no more connection between the two distinct list objects.
>>> b = list(a)
>>> a is b
>>> False
Objects in Python are stored by reference—you aren't assigning the value of a to b, but a pointer to the object that a is pointing to.
To emulate assignation by value, you can make a copy like so:
import copy
b = copy.copy(a)
# now the code works as "expected"
Be aware this has performance disadvantages.
In the case of an array, there's a special method that relies on slices:
b = a[:]
# code also works as expected here
Update– In addition to this, with some objects you can use the constructor—this includes lists:
b = list(a)
Short answer - Pointers.
When you type b = a it is setting b to look at the same array that a looks at. You have to make a new array with copies of the elements to separate them. In this case, something like b = [n for n in a] would work fine. For more complex operations you may want to check out http://docs.python.org/library/copy.html.
You might want to look at this link. The problem you have here is a and b both point to the same memory location, so changing one changes the other. Instead, you want to do something like this:
a = [1,2]
b = list(a)
a is a pointer to the list [1,2].
When you do the assignment b = a the value of b is the address of the list [1,2].
So when you do a.append(3) you are not actually changing a, you are changing the list that a points to. Since a and b both point to the same list, they both appear to change when you modify the other.
If you simply want to copy the contents of list a to b, instead of making b a pointer to a:
b = a[:]
Using the slice operator will copy the contents of the list into b such that you example would become:
a = [1,2]
b = a[:]
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2]
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 4 years ago.
When I ran this script (Python v2.6):
a = [1,2]
b = a
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2,3]
I expected print b to output [1,2]. Why did b get changed when all I did was change a? Is b permanently tied to a? If so, can I make them independent? How?
Memory management in Python involves a private heap memory location containing all Python objects and data structures.
Python's runtime only deals in references to objects (which all live in the heap): what goes on Python's stack are always references to values that live elsewhere.
>>> a = [1, 2]
>>> b = a
>>> a.append(3)
Here we can clearly see that the variable b is bound to the same object as a.
You can use the is operator to tests if two objects are physically the same, that means if they have the same address in memory. This can also be tested also using the id() function.
>>> a is b
>>> True
>>> id(a) == id(b)
>>> True
So, in this case, you must explicitly ask for a copy.
Once you've done that, there will be no more connection between the two distinct list objects.
>>> b = list(a)
>>> a is b
>>> False
Objects in Python are stored by reference—you aren't assigning the value of a to b, but a pointer to the object that a is pointing to.
To emulate assignation by value, you can make a copy like so:
import copy
b = copy.copy(a)
# now the code works as "expected"
Be aware this has performance disadvantages.
In the case of an array, there's a special method that relies on slices:
b = a[:]
# code also works as expected here
Update– In addition to this, with some objects you can use the constructor—this includes lists:
b = list(a)
Short answer - Pointers.
When you type b = a it is setting b to look at the same array that a looks at. You have to make a new array with copies of the elements to separate them. In this case, something like b = [n for n in a] would work fine. For more complex operations you may want to check out http://docs.python.org/library/copy.html.
You might want to look at this link. The problem you have here is a and b both point to the same memory location, so changing one changes the other. Instead, you want to do something like this:
a = [1,2]
b = list(a)
a is a pointer to the list [1,2].
When you do the assignment b = a the value of b is the address of the list [1,2].
So when you do a.append(3) you are not actually changing a, you are changing the list that a points to. Since a and b both point to the same list, they both appear to change when you modify the other.
If you simply want to copy the contents of list a to b, instead of making b a pointer to a:
b = a[:]
Using the slice operator will copy the contents of the list into b such that you example would become:
a = [1,2]
b = a[:]
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2]
This question already has answers here:
What is the difference between shallow copy, deepcopy and normal assignment operation?
(12 answers)
Closed 8 years ago.
I was under the impression that deepcopy copied everything recursively down a tree, but I came upon a situation that seemed to go against what I previously believed.
>>> item = "hello"
>>> a["hello"] = item
>>> b = copy.deepcopy(a)
>>> id(a)
31995776
>>> id(b)
32733616 # I expected this
>>> id(a["hello"])
140651836041376
>>> id(b["hello"])
140651836041376 # I did not expect this
The id of a and b are different, which I expected, but the internal item is still the same object. Does deepcopy only copy to a certain depth? Or is this something specific to the way Python stores strings? (I got a similar result with integers as well)
deepcopy only needs to create copies of mutable objects, like lists and dictionaries. Strings and integers are immutable; they can't be changed in-place, so there's no need to explicitly create a copy, and a reference to the same object is inserted instead.
Here is a quick demo, showing the difference between lists (mutable) and tuples (immutable):
>>> import copy
>>> l = [[1, 2], (3, 4)]
>>> l2 = copy.deepcopy(l)
>>> l2[0] is l[0]
False # created new list
>>> l2[1] is l[1]
True # didn't create new tuple
This question already has an answer here:
Understanding mutability in Python [closed]
(1 answer)
Closed 9 years ago.
My question is more of an understanding question than a strict programming question.
I know that python variables are actually pointers, which means they don't actually store a value, but rather point to the place in memory where that value is stored.
What i can't figure out is how the following 2 cases differ:
>>> a = 3
>>> b = a
>>> a
3
>>> b
3
>>>b = 4
>>> b
4
>>> a
3
The new value assigned to 'b' does not change the value pointed to by 'a'. As oppose to:
>>> a = [1,2,3]
>>> b = a
>>> a
[1,2,3]
>>> b
[1,2,3]
>>> b.append(4)
>>> b
[1,2,3,4]
>>> a
[1,2,3,4]
The new value assigned to b changed the value pointed to by a
Calling b.append doesn't assign b to a new list. It still points to the same position in memory.
>>> b = [1,2,3]
>>> id(b)
36586568L
>>> b.append(4)
>>> id(b)
36586568L
Since it is the underlying data that changes, any other identifiers also pointing to that data will be affected.
This has been covered many times before. Short answer is that they aren't strictly pointers. They are more like labels. In your top case, b is re-labeled to 4 and thus changes. In your bottom case (with the array) b is not re-labeled, but only it's contents appended to. That's why arrays seem to act differently.
Python "variables" ("binding" would be a more appropriate term) are not pointers, they are key->value pairs in a namespace. How the namespace and lookup are implemented is, well, an implementation detail, but you can consider it's a hash table (Python's dict).
The new value assigned to b changed the value pointed to by a
Where do you see the assignement operator in b.append(4) ? You're not rebinding b, you are mutating it. It's still the same list object that is bound to both names a and b.