#๐Ÿ”’ partially copy an object

61 messages ยท Page 1 of 1 (latest)

unkempt sandal
#

I want this:

class Obj:
  def __init__(self): 
    self.number = 10
    self.seq = [1,2,3]
    self.seq2 = [3,4,5]
  def calculate(self): 
    return sum(self.seq) + self.number + len(self.seq2)

obj = Obj()
# so I want to semi-copy `obj`. With the only difference that `seq` refers to a differnt object. So for example
obj2 = semicopy(obj)
# now if I say
obj2.seq = [0.1, 0.2, 0.3] # it will only change on obj2
# but if I say
obj1.seq2 = [0.3, 0.4, 0.5] # it will change on both because it isnt copied
pearl topazBOT
#

@unkempt sandal

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

pliant socket
#

that should already be the case

#

a new list will be constructed for each object

unkempt sandal
#

not a new copy

pliant socket
#

wait what

unkempt sandal
#

but not like that, I want it to just be a reference to obj.seq2

pliant socket
#

you just said you wanted it to be a different object

#

"With the only difference that seq refers to a differnt object"

unkempt sandal
pliant socket
#

so seq should be a shared list between all the instances?

unkempt sandal
#

well I can do that

#

actually

#

yeah

pliant socket
#

yeah, then use a class var

#

otherwise this sounds like an xy problem

#

!xy

pearl topazBOT
#
xy-problem

The XY problem can be summarised as asking about your attempted solution, rather than your actual problem.

Often programmers will get distracted with a potential solution they've come up with, and will try asking for help getting it to work. However, it's possible this solution either wouldn't work as they expect, or there's a much better solution instead.

For more information and examples, see http://xyproblem.info/.

unkempt sandal
#

no, I can do that by copying the object, and then setting that list to a copy, all other things refer to same objects

#

I need it to be a reference to a variable

pliant socket
#

you can't reference a variable

#

only its data

#

a variable is already a reference to data

unkempt sandal
# pliant socket otherwise this sounds like an xy problem

okay I have an array and it works like this: I have a bunch of transforms, where I set some value to the array, they get applied to that value. For example transform that multiplies that value by 2, meaning whatever value I set to my array, it gets multiplied by 2. And when I access my array, opposite transform gets applied so it gets divided by 2. Now there is a lot of other logic on both transformed and untransformed arrays

#

and I want to create a new array which is just one of my arrays but with an additional transform on top

#

But I want it to still refer to same underlying data

pliant socket
#

I'd create an inherited class then. It's fundamentally different behaviour

#

and then you could make your new list a property

#

!e

class Obj:

    def __init__(self):
        self.seq = [1, 2, 3]


class TransObj(Obj):

    def __init__(self, seq):
        self._seq = seq

    @property
    def seq(self):
        return [i * 2 for i in self._seq]



obj = Obj()
trans_obj = TransObj(obj.seq)

print(trans_obj.seq)
pearl topazBOT
pliant socket
#

something like this

unkempt sandal
#

so then I need to create a new object with the same class as the original object, so I do this, new object = existing object.__class__.__new__(existing object.__class__), and then I would copy all existing objects stuff over except this new thing, but isn't that slow for a lot of attributes, is there maybe a better way to do this

#

no that won't work

#

and then I could say new object.getattr = function that gets it from existing object unless its that attribute that i want to copy

#

okay

#

obj2.__getattr__ = replace_getattr this part doesnt replace anything

pliant socket
#

!e

class Obj:

    def __init__(self):
        self.seq = [1, 2, 3]


class TransObj(Obj):

    def __init__(self, seq):
        self._seq = seq

    @property
    def seq(self):
        return [i * 2 for i in self._seq]



obj = Obj()
trans_obj = TransObj(obj.seq)

print(trans_obj.seq)
obj.seq.append(10)
print(trans_obj.seq)
pearl topazBOT
unkempt sandal
unkempt sandal
#

okay

#

I have a good example

#

so lets say I have a dictionary

#

dict(a = [1,2,3], b = [4,5,6])

#

I want to create a new dictionary where b is a copy but a is not

pliant socket
#

are the amount of sequences dynamic?

unkempt sandal
#
from functools import partial


class Wrap:
    def __init__(self, obj):
        self.obj = obj
        self.x =7
    def __getattr__(self, attr):
        attr = getattr(self.obj, attr)
        if callable(attr):
            return partial(attr, self)
        return attr

class A:
    x = 5
    def stuff(self): return self.x

w = Wrap(A)

w.stuff()

this seems to work (for some reason)

#

says 7 correctly

#

I don't understand why it works tho

#

but I won't complain

#

the only issue is that I have some callables that are not methods and it is going to be annoyhing to filter them

#

I found a fix

#

if attr not in self.obj.dict: do the partial thing

#

there is still an issue which is that dunder methods i have to define them manually

unkempt sandal
#

full version works even nested

import functools

class AttrHook:
    def __init__(self, obj):
        self.obj = obj
        self.x = 9

    def __getattr__(self, name):
        attr = getattr(self.obj, name)
        if callable(attr) and name not in self.obj.__dict__:
            return functools.partial(attr, self)
        return attr

class A:
    def __init__(self): self.x = 0
    def stuff(self, *args, **kwargs): 
        print(f'{self = }')
        print(f'{args = }')
        print(f'{kwargs = }')
        n = args[0]
        return self.x, n

w = AttrHook(A)
w2 = AttrHook(w)
w2.stuff(6) # says (9, 6) so it works
pearl topazBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.