6

I have a program for which it would be most sensible to overwrite an object in memory instead of changing it, or redirecting a reference to it.

Basically, if I was writing C++, I would have multiple pointers all referring to the same address in memory. I would like to overwrite the contents at that address.

I would like to be able to do this from within the object itself as well.

i.e.

class MyClass
    def __init__(self):
        pass

    def overwrite(self,otherObjectOfTypeMyClass):
       #after this operation, all references to self now point to otherObjectOfTypeMyClass
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
pixelpax
  • 1,435
  • 13
  • 22
  • 1
    How about making MyClass not hold any data at all, other than a private reference to a MyClassImplementation object, and keep all of your actual data inside the MyClassImplementation object. Then to "overwrite the MyClass object" you would just replace its private MyClassImplementation object with a different one. (It's not really "overwriting" per se but it would give the same effect as far as all external holders of the MyClass object are concerned) – Jeremy Friesner Mar 27 '16 at 03:27
  • 1
    It's pretty unclear where in your question you refer to variables and where you refer to the actual object. Also, which of the objects are classes and which of them are class instances? Further, can you give example code showing how it's supposed to work? Also, why did you add tags `C++` and `C` to your question!? – Ulrich Eckhardt Mar 27 '16 at 06:38
  • You're right, the phrasing of the problem is confusing, I will try to reword. The reason why I tag cpp is because the premise of the problem is to perform an operation with python which is common and trivial in cpp. – pixelpax Mar 27 '16 at 16:18
  • Accessing an object by memory location, or writing an object to a memory location is not possible in Python. You can implement a class in C and use it in Python if you *need* this behavior. – Jared Goguen Mar 27 '16 at 18:02

3 Answers3

3

Unlike C++, memory management is not under your control in Python. And in general, that is a good thing. Not having to worry about memory is one of the big benefits for those of us who started in C.

In python what we call variables are really labels referring to objects. So if you want to change an object that is not immutable (like a list), that should work out-of-the-box in Python.

However, you cannot really generally overwrite objects in Python. Creating a new object will use free memory. And memory that is in use will only be garbage-collected once it has no references to it.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
  • This makes sense to me, and I understand that what I'm trying to do is.... unpythonic. Can you think of any hacky way to do it anyways? I have many references to a single object/address-in-memory and I don't have access to all of them within the scope that I'm making changes in. – pixelpax Mar 27 '16 at 18:54
  • @user2130130 You *could* call `gc.referrers` to get all the names that reference your object. But that is a terrible hack for reasons mentioned in the documentation. It says *"Avoid using `get_referrers` for any purpose other than debugging"*. – Roland Smith Mar 27 '16 at 19:05
  • I came up with a kludge solution below-- would love your input on it. It doesn't overwrite an address per se, but I think it effectively accomplishes the same thing from a high level POV. – pixelpax Mar 27 '16 at 19:08
  • You are basically just *changing* an object (as I mentioned in the second paragraph), not *replacing* it by an object of a different type. – Roland Smith Mar 27 '16 at 19:11
  • You're absolutely correct, but I am only interested in replacing it with an object of the same type (Hence variable name in first example). – pixelpax Mar 27 '16 at 19:26
  • That works out-of-the-box. :-) – Roland Smith Mar 27 '16 at 19:28
2

OK, I've found a solution that seems to work for my specific usage. I don't know the internals of python well enough to say whether this would break in unexpected ways. I would be interested in hearing why or why not this would be a dangerous thing to do. I'd also be interested if anyone has any ideas of scenarios in which this would not do what I'm expecting it to. I will wait to mark this correct for a few days in case anyone thinks that it's actually catastrophic.

def replaceobject(obj1,obj2):
    #Replaces obj1 with obj2
    obj1.__dict__ = obj2.__dict__


class MyClass:
    def __init__(self):
        self.attr0 = None
        self.attr1 = None
        self.attr2 = None
        self.attr3 = None

    def set_some_attrs(self):
        self.attr0 = 0
        self.attr1 = "1"
        self.attr2 = {"2":2}
        self.attr3 = [3]

#Set up scenario, three objects of the same type, one points to a different address
A = MyClass()
A.set_some_attrs()
C = A
B = MyClass()

#Make replacement and spit contents
replaceobject(B,A)
print B.attr0 #=> 0
print B.attr1 #=> "1"
print B.attr2 #=> {"2":2}
print B.attr3 #=> [3]

#Modify the replaced object and changes are reflected
B.attr2 = "made a change"
print A.attr2 #=> "made a change"
print C.attr2 #=> "made a change"
pixelpax
  • 1,435
  • 13
  • 22
  • This is going to link `obj1` and `obj2` together, which may be desired. In general, saving memory by avoiding creating an object is usually not worth it. I think a more Pythonic solution would to either (i) just use the original object, or (ii) use `copy.copy` to copy the original object (if you want linkage). Using `copy.deepcopy` will prevent linkage. – Jared Goguen Mar 27 '16 at 19:29
  • I agree with you, but It's not that I want to save memory-- I want to avoid the added computational complexity of searching the containing data structures each time I want to "replace" an object. – pixelpax Mar 27 '16 at 20:03
0

Python supports multiple inheritance, so how about just making myClass a wrapper for A and B? May seem like an overkill, you might introduce the diamond problem if A and B are using similar interface, but this is the as close to "overriding" as I can think of.

Somrlik
  • 680
  • 5
  • 13