Unnamed Python Objects Have the Same Id

Unnamed Python objects have the same id

From the doc of id(object):

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

Since the two ranges inside the id() calls have non-overlapping lifetimes, their id values may be the same.

The two ranges assigned to variables have overlapping lifetimes so they must have different id values.

Edit:

A look into the C sources shows us builtin_id:

builtin_id(PyObject *self, PyObject *v)
{
return PyLong_FromVoidPtr(v);
}

and for PyLong_FromVoidPtr.

PyLong_FromVoidPtr(void *p)
{
#if SIZEOF_VOID_P <= SIZEOF_LONG
return PyLong_FromUnsignedLong((unsigned long)(Py_uintptr_t)p);
#else

#ifndef HAVE_LONG_LONG
# error "PyLong_FromVoidPtr: sizeof(void*) > sizeof(long), but no long long"
#endif
#if SIZEOF_LONG_LONG < SIZEOF_VOID_P
# error "PyLong_FromVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)"
#endif
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)(Py_uintptr_t)p);
#endif /* SIZEOF_VOID_P <= SIZEOF_LONG */

}

So the ID is a memory address.

Horrible redraw performance of the DataGridView on one of my two screens

You just need to make a custom class based off of DataGridView so you can enable its DoubleBuffering. That's it!


class CustomDataGridView: DataGridView
{
public CustomDataGridView()
{
DoubleBuffered = true;
}
}

As long as all of my instances of the grid are using this custom version, all is well. If I ever run into a situation caused by this where I'm not able to use the subclass solution (if I don't have the code), I suppose I could try to inject that control onto the form :) (although I'll be more likely to try using reflection to force the DoubleBuffered property on from the outside to once again avoid the dependency).

It is sad that such a trivially simple thing ate up so much of my time...

Note: Making the answer an answer so the question can be marked as answered

Why do different methods of same object have the same 'id'?

The same memory location is being used by Python for methods a.f and a.g, which are **two objects with non-overlapping lifetimes*, so id returns same identity for both of them. See more detailed explanations below.

From the documentation for the is operator:

The operators is and is not test for object identity: x is y is true
if and only if x and y are the same object.

From the documentation for the is id

Return the “identity” of an object. This is an integer (or long
integer) which is guaranteed to be unique and constant for this object
during its lifetime. Two objects with non-overlapping lifetimes may
have the same id() value.

Explanations:

Whenever you look up a method via class.name or instance.name, the method object is created a-new. Python uses the descriptor protocol to wrap the function in a method object each time.

So, when you look up id(a.f) or id(a.g), a new method object is created.

  1. When you grubbing id of a.f, a copy of it is created in memory. This memory location is returned by id.
  2. Since there are no references to the newly created method, it reclaimed by the GC (now memory address is available again).
  3. After you getting id of a.g, a copy of it is created at the same memory address, which you retrieve using id again.
  4. You've got truthy id's comparison.

Good luck!

Python: different objects get the same id

This is an interesting question, but it's well explained in wtfpython.

When a and b are set to "hello" in the same line, the Python interpreter creates a new object, then references the second variable at the same time. If you do it on separate lines, it doesn't "know" that there's already hello as an object (because "hello" is not implicitly interned as per the facts mentioned above). It's a compiler optimization and specifically applies to the interactive environment.

One thing that differs is that in IPython, things might be a bit different from direct Python REPL, so this explains the difference in id in your first two inputs.

The 'is' operator is not working on objects with the same identity

After id(300) is executed, no more references to 300 exist, so the id is freed. When you execute id(6), it gets that same chunk of memory and stores 6 instead. When you do -300 is 6, -300 and 6 are both referenced at the same time, so they won't have the same address anymore.

If you keep references to both -300 and 6, this happens:

>>> a, b = -300, 6
>>> id(a)
some number
>>> id(b)
some different number; 6 is still in the other memory address.

Note: In CPython, numbers from -5 to 256 (I think) are cached, and will always have the same address, so this will not happen.

How does `is` work in the case of ephemeral objects sharing the same memory address?

Two unmutable objects, sharing the same address, would, as you are concerned, be indistinguishable from each other.

The thing is that when you do a[:] is a[:] both objetcts are not at the same address - in order for the identity operator is to compare both objects, both operands have to exist - so, there is still a reference to the object at the left hand side when the native code for is is actually run.

On the other hand, when you do id(a[:]),id(a[:]) the object inside the parentheses on the first call is left without any references as soon as the id function call is done, and is destroyed, freeing the memory block to be used by the second a[:].

Why does `is` return False even though id's are identical?

Just re-entering my comment as "an answer":

Simply because the same memory is reused for the objects: in the last two statements, the lifetimes of the objects whose id's you're obtaining do not overlap, so Python is free to (re)use the same memory for them.

id() vs `is` operator. Is it safe to compare `id`s? Does the same `id` mean the same object?

According to the id() documentation, an id is only guaranteed to be unique

  1. for the lifetime of the specific object, and
  2. within a specific interpreter instance

As such, comparing ids is not safe unless you also somehow ensure that both objects whose ids are taken are still alive at the time of comparison (and are associated with the same Python interpreter instance, but you need to really try to make that become false).

Which is exactly what is does -- which makes comparing ids redundant. If you cannot use the is syntax for whatever reason, there's always operator.is_.


Now, whether an object is still alive at the time of comparison is not always obvious (and sometimes is grossly non-obvious):

  • Accessing some attributes (e.g. bound methods of an object) creates a new object each time. So, the result's id may or may not be the same on each attribute access.

    Example:

    >>> class C(object): pass
    >>> c=C()
    >>> c.a=1

    >>> c.a is c.a
    True # same object each time

    >>> c.__init__ is c.__init__
    False # a different object each time

    # The above two are not the only possible cases.
    # An attribute may be implemented to sometimes return the same object
    # and sometimes a different one:
    @property
    def page(self):
    if check_for_new_version():
    self._page=get_new_version()
    return self._page
  • If an object is created as a result of calculating an expression and not saved anywhere, it's immediately discarded,1 and any object created after that can take up its id.

    • This is even true within the same code line. E.g. the result of id(create_foo()) == id(create_bar()) is undefined.

      Example:

      >>> id([])     #the list object is discarded when id() returns
      39733320L
      >>> id([]) #a new, unrelated object is created (and discarded, too)
      39733320L #its id can happen to be the same
      >>> id([[]])
      39733640L #or not
      >>> id([])
      39733640L #you never really know

Due to the above safety requirements when comparing ids, saving an id instead of the object is not very useful because you have to save a reference to the object itself anyway -- to ensure that it stays alive. Neither is there any performance gain: is implementation is as simple as comparing pointers.


Finally, as an internal optimization (and implementation detail, so this may differ between implementations and releases), CPython reuses some often-used simple objects of immutable types. As of this writing, that includes small integers and some strings. So even if you got them from different places, their ids might coincide.

This does not (technically) violate the above id() documentation's uniqueness promises: the reused object stays alive through all the reuses.

This is also not a big deal because whether two variables point to the same object or not is only practical to know if the object is mutable: if two variables point to the same mutable object, mutating one will (unexpectedly) change the other, too. Immutable types don't have that problem, so for them, it doesn't matter if two variables point to two identical objects or to the same one.


1Sometimes, this is called "unnamed expression".



Related Topics



Leave a reply



Submit