Jump to content
  • Advertisement
Sign in to follow this  
Gage64

[Python] Slice notation and object copies

This topic is 3775 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've decided to try and learn Python. I'm using the tutorial in the documentation and there's something I don't quite understand. When using slice notation, it looks like I am sometimes getting a copy of the object and other times I get the object itself. Sounds vague, I know, but the following example shows what I mean. If I write the following in the python shell:
a = [1, 2, 3]
a[:] = [4, 5, 6]
a
the output is: [4, 5, 6], so the object 'a' was modified, but if I write the following:
a[:].append(7)
a
the output is: [4, 5, 6], so 'a' was not modified, which I assume is because append() was called on a copy of 'a' returned by the [:]. So what's going on? Another question: Why does Python allow me to write the second code snippet? I mean, modifying a temporary copy of 'a' doesn't make sense, so shouldn't this be flagged as an error (like it does in C++)? Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Gage64
modifying a temporary copy of 'a' doesn't make sense, so shouldn't this be flagged as an error (like it does in C++)?

Modifying temporary copies is completely legal in C++:

std::vector<int> a;
a.push_back(1);

std::vector<int>(a).push_back(2); // !!!



Share this post


Link to post
Share on other sites
Quote:
Original post by bubu LV
Modifying temporary copies is completely legal in C++


I just tried a few examples and you're right. I was going by this (under the Temporaries section), but it looks like it's incorrect (even though what is written there makes sense).

Share this post


Link to post
Share on other sites
Python objects have several functions available to them in order to deal with slices including the __getslice__ and __setslice__ methods. What you're doing in your first example is (implicitly) calling the __setslice__ method - it takes a slice of an object, modifies it, and reinserts it into the object. In your second example, you are implicitly calling __getslice__ which returns a copy of the slice selected.

Basically, whenever you have a assign operation following a slice, the __setslice__ method is called. Otherwise the __getslice__ method is called.

Share this post


Link to post
Share on other sites
CrimsonSun - Thank you for the thorough explanation, I understand now, though I still think it's strange that the second snippet doesn't cause an error.

Share this post


Link to post
Share on other sites
In your second example, you're just appending 7 to a temporary copy. If you don't do anything with this temporary, then the temporary is just thrown away. You can assign this modified temporary to a variable:

a = [1, 2, 3]
b = a[:].append(7)


Now b contains [1, 2, 3, 7].

Share this post


Link to post
Share on other sites
Quote:
a = [1, 2, 3]

b = a[:].append(7)



Now b contains [1, 2, 3, 7].


I just typed this, and the value of b is None because append() doesn't return anything.

Share this post


Link to post
Share on other sites
You're absolutely right, I made a mistake above - append doesn't return anything, so b gets the value of None. Please disregard my above post.

However, you can always assign a variable to the return value of a slice. Notice also that this is the only way to get a copy of a sequence such as a list.

If you have:
a = [1, 2, 3]

And then assign b to a:
b = a

Then you've assigned b to the same list as that of a. So anything that modifies the list accessed from a also modifies the list accessed from b (they are the same list!):

b[1] = 4
Now both a and b contain the list [1, 4, 3]. If you want to have a copy of the sequence in a (such that modification of the list accessed by a does not modify the list accessed by b), you just take the default slice:

b = a[:]

Share this post


Link to post
Share on other sites
Quote:
Original post by CrimsonSun
However, you can always assign a variable to the return value of a slice. Notice also that this is the only way to get a copy of a sequence such as a list.

If you have:
a = [1, 2, 3]

And then assign b to a:
b = a

Then you've assigned b to the same list as that of a. So anything that modifies the list accessed from a also modifies the list accessed from b (they are the same list!):

b[1] = 4
Now both a and b contain the list [1, 4, 3]. If you want to have a copy of the sequence in a (such that modification of the list accessed by a does not modify the list accessed by b), you just take the default slice:

b = a[:]


I don't understand how any of that is relevant to my question :)

If you write:

a[:].append(5)

you are modifying a temporary object that will cease to exist after that statement (or at least it will no longer be accessible). I can't think of an example where you would want to do this, so if you wrote something like this, you probably made a mistake, which is why I think the interpreter should flag this as an error.

Thanks for your help so far.

Share this post


Link to post
Share on other sites
It's not trivial for an interpreter to spot that such things are mistakes. Sometimes the function call on the right (eg. append() ) has side-effects that you're relying upon, so it can't assume it was an error. Maybe you were just testing the append() functionality, for example!

Share this post


Link to post
Share on other sites

This topic is 3775 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!