Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: How to override a memory at a pointer location?

Tags:

python

memory

Given the following code

class Test():
    def __init__(self, foo):
        self._foo = foo

a = Test("bar") # id(a) returns e.g. 2243221358240
b = Test("rab") # id(b) returns e.g. 2243221358184

I want to copy the object being referenced by b to the location of a such that id(a) still returns the orignal address, but a._foo returns rab.

What is the "pythonic" way to do so?
Is this possible in Python at all?

like image 283
Boern Avatar asked May 18 '26 15:05

Boern


1 Answers

Python isn't C and it doesn't make sense to talk about copying one instance's memory on top of another's. You can achieve a similar result by copying all the attributes from one instance to another.

In most Python objects, the attributes are stored in an instance attribute called __dict__, except when there's a __slots__ attribute on the class, which defines the names of the allowed attributes.

Many built-in Python objects are implemented in C and so don't have either of these attributes. These generally can't be copied by attribute in any sensible automated fashion.

With these caveats, you could do something like the following:

def copy_attributes(obj1, obj2):
    if not isinstance(obj1, type(obj2)) and not isinstance(obj2, type(obj1)):
        raise TypeError("source and target object types must be related somehow")
    # fast path if both have __dict__
    if hasattr(obj1, "__dict__") and hasattr(obj2, "__dict__"):
        obj2.__dict__.update(obj1.__dict__)
        return
    # copy one attribute at a time
    names = getattr(type(obj1), "__slots__", ()) and getattr(obj1, "__dict__", ())
    slots = set(getattr(type(obj2), "__slots__", ()))
    if slots and not all(name in slots for name in names):
        raise AttributeError("target lacks a slot for an attribute from source")
    for name in names:
        setattr(obj2, getattr(obj1, name))

The way I've written this function, the two instances must be related (one a subclass of the other's type). This increases the likelihood that this will actually work, although depending on how the classes are set up, it may or may not result in a useful configuration of obj2 unless they are exactly the same type. That is, attributes that obj2 has but obj1 doesn't will retain their original values, and this may produce an inconsistent object. You might prefer more strict type-checking: if type(obj1) is not type(obj2) for example.

if the type of obj2 has __slots__ and obj1 has attributes that aren't permitted in obj2, you'll get an error trying to set those attributes. In this case, I check to make sure all the attributes about to be copied exist in __slots__. Otherwise you could end up without all attributes copied.

You could remove some or all of these safety checks for performance reasons, if you know the types you'll be using.

Note that attributes defined on the class, including methods, aren't copied by this function; it copies instance attributes only. The copies are shallow, so mutable objects are shared. You can add copy.copy or copy.deepcopy calls if this is important.

like image 155
kindall Avatar answered May 22 '26 01:05

kindall



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!