Python convert string back to object

Question:

I have an object:

c = Character(...)

I convert it to a string by using:

p = "{0}".format(c)
print(p)
 
>>> <Character.Character object at 0x000002267ED6DA50>

How do i get the object back so i can run this code?

p.get_name()
Asked By: Code Pal

||

Answers:

You absolutely can if you are using CPython (where the id is the memory address). Different implementations may not work the same way.

>>> import ctypes
>>> class A:
...   pass
... 
>>> a = A()
>>> id(a)
140669136944864
>>> b = ctypes.cast(id(a), ctypes.py_object).value
>>> b
<__main__.A object at 0x7ff015f03ee0>
>>> a is b
True

So we’ve de-referenced the id of a back into a py_object and snagged its value.

Answered By: g.d.d.c

If your main goal is to serialize and deserialize objects. (ie. turn objects into string and back while preserving all the data and functions) your can use pickle. You can use pickle.dumps to convert any object into a string and pickle.loads to convert it back into an object. docs

>>> import pickle
>>> class Student:
...     def __init__(self, name, age):
...             self.name = name
...             self.age  = age
... 
>>> a = Student("name", 20)
>>> pickle.dumps(a)
b'x80x04x951x00x00x00x00x00x00x00x8cx08__main__x94x8cx07Studentx94x93x94)x81x94}x94(x8cx04namex94hx05x8cx03agex94Kx14ub.'
>>> s = pickle.dumps(a)
>>> b = pickle.loads(s)
>>> b
<__main__.Student object at 0x7f04a856c910>
>>> b.name == a.name and b.age == a.age
True
Answered By: Deera Wijesundara

It is not possible in the general case to use the ID embedded in the default __str__ implementation to retrieve an object.

Borrowing from g.d.d.c’s answer, let’s define a function to do this:

import ctypes

def get_object_by_id(obj_id):
    return ctypes.cast(obj_id, ctypes.py_object).value

def get_object_by_repr(obj_repr):
    return get_object_by_id(int(obj_repr[-19:-1], 16))

It works for any object that is still in scope, provided that it’s using the default __repr__/__str__ implementation that includes the hex-encoded id at the end of the string:

>>> class A:
...     pass
...
>>> a = A()
>>> r = str(a)
>>> r
'<__main__.A object at 0x000001C584E8BC10>'
>>> get_object_by_repr(r)
<__main__.A object at 0x000001C584E8BC10>

But what if our original A has gone out of scope?

>>> def get_a_repr():
...     a = A()
...     return str(a)
...
>>> r = get_a_repr()
>>> get_object_by_repr(r)

(crash)
(and I don't mean an uncaught exception, I mean Python itself crashes)

You don’t necessarily need to define a in a function to do this; it also can happen if you just rebind a in the local scope (note: GC isn’t necessarily guaranteed to happen as soon as you rebind the variable, so this may not behave 100% deterministically, but the below is a real example):

>>> a = A()
>>> r = str(a)
>>> get_object_by_repr(r)
<__main__.A object at 0x000001C73C73BBE0>
>>> a = A()
>>> get_object_by_repr(r)
<__main__.A object at 0x000001C73C73BBE0>
>>> a
<__main__.A object at 0x000001C73C73B9A0>
>>> get_object_by_repr(r)

(crash)

The reason this happens is that unlike C, Python garbage-collects objects that have gone out of scope and which do not have any references — and the id value itself (which is just an int), or the string representation of the object that has the id embedded in it, is not recognized by the interpreter as a live reference! And because ctypes lets you reach right into the guts of the interpreter (usually a bad idea if you don’t know exactly what you’re doing), you’re telling it to dereference a pointer to freed memory, and it crashes.

In other situations, you might actually get the far more insidious bug of getting a different object because that memory address has since been repurposed to hold something else (I’m not sure how likely this is).

To actually solve the problem of turning a str() representation into the original object, the object must be serialized, i.e. turned into a string that contains all the data needed to reconstruct an exact copy of the object, even if the original object no longer exists. How to do this depends entirely on the actual content of the object, but a pretty standard (language-agnostic) solution is to make the class JSON-serializable; check out How to make a class JSON serializable.

Answered By: Samwise
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.