Python How can I distinguish between two list items that point to the same object?

I have a Ring structure implemented as follows (based on the cookbook recipe I found):

class Ring(list): def turn(self): last = self.pop(0) self.append(last) def setTop(self, objectReference): if objectReference not in self: raise ValueError, "object is not in ring" while self[0] is not objectReference: self.turn() 

Let's say I do the following:

 x = Ring([1,2,3,4,4]) x.setTop(4) 

My code will always set the first 4 (currently x [3]) to x [0]. It seems (through an object identifier and a hash identifier between x [3] and x [4]) that Python reuses 4 objects.

How do I tell Python that I really want the second 4 (currently x [4]) to be on top?

Sorry for the basic question ... one of the obstacles to becoming a self-taught newbie.

Thanks,

Mike

=== EDIT ===

For what it's worth, I dropped the setTop method from the class. I added it to the standard recipes, thinking "hey, that would be neat and could be helpful." Like the answers (like “what's the difference” that is in place) and my own experience with using the structure show this is a shitty method that does not support any of my use cases.

In other words, adding something because I can instead fulfill the need = crash.

+4
source share
7 answers

From Python Learning 4th Edition - Chapter 6:

At least conceptually, every time you create a new value in a script by running an expression, Python creates a new object (i.e. a piece of memory) to represent this value. Inside, like optimization, Python caches and reuses certain types of non-removable objects, such as small integers and strings (each 0 is not really a new piece of memory - more on this caching behavior later). But, from a logical point of view, it works as if each value of the result of the expression is a separate object, and each object is a distinct part of the memory.

The question is ..

 if x[3] is x[4]: print "What the difference?" 
+4
source

If you know you want a second, then do

 x = Ring([1,2,3,4,4]) x.setTop(4) x.turn() x.setTop(4) 

You can improve setTop () to take an extra parameter and do it inside.

+2
source

Cpython has an "integer cache" for small integers, so values ​​from -5 to 255 (may vary depending on the version or implementation of Python) reuse the same object for the given value. That is, all 4s are the same int-object with a value of 4. This is done to reduce the need to create an object.

There are several ways around this.

  • You can use long integers (e.g. write 4L instead of 4). Python does not use cache for long integers. (You can also use float, as they are also not cached.) However, if you do a lot of math with numbers, this can lead to poor performance.
  • You can wrap each element in a list or tuple (conveniently enough, because there is a simple syntax for this, although it is more syntax than long integers or floating ones).
  • You can create your own object to wrap an integer. An object will have all the same methods as an integer (therefore, it works like an integer in mathematics, comparisons, printing, etc.), but each instance will be unique.

I personally like to use long int in this case. You can easily convert integers to longs in the constructor and to any method that adds an element.

+1
source

Sounds like you always want to rotate at least once, right? If so, rewrite the setTop method as follows:

 def setTop(self, objectReference): if objectReference not in self: raise ValueError, "object is not in ring" self.turn() while self[0] is not objectReference: self.turn() 

Then it cyclically moves between the expected states:

 >>> x = Ring([1,2,3,4,4]) >>> x [1, 2, 3, 4, 4] >>> x.setTop(4) >>> x [4, 4, 1, 2, 3] >>> x.setTop(4) >>> x [4, 1, 2, 3, 4] >>> x.setTop(4) >>> x [4, 4, 1, 2, 3] 
+1
source

I also don’t know enough to be sure, but I think that numbers, even if beeing objects, are the same objects when used at different points in your code. Why do I think so? Take a look:

 >>> type(2) <type 'int'> >>> type(lambda x:x) <type 'function'> >>> 2 is 2 True >>> (lambda x: x) is (lambda x: x) False 

2 objects are not identical when created twice. But the numbers are not created by you, they are already there. And it makes no sense to select one 4 different object from another 4 . At least I don’t see it.

0
source

For small numbers, python will have an object cache to avoid the cost of creating new objects. They will have the same object identifier. Java does this too. You need a way to avoid this.

0
source

Python reuses small integers and short strings. As far as I know, there is no way around this - you have to get along with it, and the fact that setTop only rotates until the first match. I suppose you could add the optinal parameter, n = 1 and rotate until there is n th. But that doesn't matter, does it?

Unrelated, consider this:

 >>> class Point(object): ... def __init__(self, x, y): ... self.x, self.y = x, y ... def __eq__(self, other): ... return (self.x == other.x and self.y == other.y) ... >>> a_ring = Ring(Point(1, 2), Point(15, -9), Point(0, 0)) >>> a_ring.seTop(Point(15, -9)) Traceback ... ... ValueError: object not in ring 

Not how it should work, right? You should use while self[0] != objectReference (which is a btw misleading name) to avoid this.

0
source

All Articles