0

Possible Duplicate:
Python: Get object by id

Typically when you see the string representation of an instance it looks something like <module.space.Class @ 0x108181bc>. I am curious if it's possible to take this string and get a handle on the instance.

Something like

 obj_instance = get_instance_form_repr("<module.space.Class @ 0x1aa031b>")

I don't believe it could be possible but if it is, it would be really useful.

Community
  • 1
  • 1
lukecampbell
  • 14,728
  • 4
  • 34
  • 32
  • 4
    Out of interest, why would you want to do this? It rings of other problems in your code. – Gareth Latty Jun 13 '12 at 15:45
  • As that answer suggests, the only likely use of an object lookup like this is a generic weakmap implementation. Python supports weakref so it's practically useless, unless you have some other idea? – Matt Esch Jun 13 '12 at 15:50
  • It's not a problem with any code, I'm just curious if it's possible. From a pure tinkering perspective. – lukecampbell Jun 13 '12 at 16:40

2 Answers2

2

You can do it for the subset that is tracked by the garbage collector at least, in a nasty and unreliable way.

def lookup_object_by_repr(myrep)
    import gc
    for obj in gc.get_objects():
        if repr(obj) == myrep:
           return obj

You can do even more things if you write a simple C extension and inspect the memory address.

schlenk
  • 7,002
  • 1
  • 25
  • 29
  • 1
    Great point. The C extension is probably a better solution for tinkering or just about any other purposes—but this one actually is as close as possible to the true inverse of the repr function. – abarnert Jun 13 '12 at 19:20
1

Of course there's no way to get an object from its repr, because any class can return anything it wants in its repr. But in the specific case where the repr has a pointer in it, you're basically asking how to get an object from a pointer. Which (in C Python, at least) is the exact same thing as asking how to get an object from its id.

There's no built-in way to do this, even though it would be pretty simple. And that's intentional, because this is almost always a bad idea.

If you think you have a practical purpose for getting an object by id, you're probably wrong. Especially since you have to deal with object lifecycle issues that are usually taken care of automatically (and behind your back, which makes it hard to take care of them manually even if you try). For example, if an object goes away, a weakref to that object nulls out, but the id is still pointing—to deallocated memory, or another object created later, or half of one object and half of another. And then of course whatever you do in C Python isn't going to work in PyPy or jython or IronPython…

But if you're just tinkering around to learn how the C Python runtime works, then this is a legitimate question, and there's a legitimate answer. Probably the best way to do it is to create a C extension module. If you don't know how to create an extension module, you really ought to learn that first, and come back to this question later. If you do, the function you want to implement is pretty simple:

static PyObject *objectFromId(PyObject *self, PyObject *args) {
  PyObject *obj;
  if (!PyArg_ParseTuple(args, "n", &obj)) return NULL;
  Py_INCREF(obj);
  return obj;
}

You could do this in Pyrex/Cython instead of C, if you wanted. Or you could just call PyObj_FromPtr directly on the _ctypes module. But if you're trying to learn how things work at this level, it makes more sense to make what's happening explicit, and to explicitly put your "dealing with C pointers" code in C.

On further thought, it you wanted to build a sort of best-guess objectFromRepr for tinkering purposes, you could. Basically:

  • Use a regex that matches the common angle-bracket form; if it matches, call objectFromId with the address.
  • Call eval.

You might want to put an intermediate step in there: for many types, the repr is in the form of a constructor call like Class(arg1, arg2), and in that case it might be better to match that form with another regex and call the constructor directly, instead of using eval. If nothing else, it's probably more instructive, and that's the point of this exercise, right?

Obviously this is an even more terrible idea in real-life code than objectFromId. It's almost always bad to use eval, and eval(repr(x)) == x is not actually guaranteed to be true, and you're actually getting a new reference to the same object in the id case but a new object with the same value in the eval case, and…

PS, After you learn how all of this works in C Python, it's probably worth doing a similar exercise in another interpreter like jython or IronPython (especially when you repr a native Java/.NET/etc. object).

abarnert
  • 354,177
  • 51
  • 601
  • 671