user3208430
user3208430

Reputation: 676

Mutable objects in python and constants

I have a class which contains data as attributes and which has a method to return a tuple containing these attributes:

class myclass(object):
    def __init__(self,a,b,c):
        self.a = a
        self.b = b
        self.c = c

    def tuple(self):
        return (self.a, self.b, self.c)

I use this class essentially as a tuple where the items (attributes) can be modified/read through their attribute name. Now I would like to create objects of this class, which would be constants and have pre-defined attribute values, which I could then assign to a variable/mutable object, thereby initializing this variable object's attributes to match the constant object, while at the same time retaining the ability to modify the attributes' values. For example I would like to do this:

constant_object = myclass(1,2,3)
variable_object = constant_object
variable_object.a = 999

Now of course this doesn't work in python, so I am wondering what is the best way to get this kind of functionality?

Upvotes: 1

Views: 616

Answers (3)

inspectorG4dget
inspectorG4dget

Reputation: 114035

Deepcopying is not entirely necessary in this case, because of the way you've setup your tuple method

class myclass(object):
    def __init__(self,a,b,c):
        self.a = a
        self.b = b
        self.c = c

    def tuple(self):
        return (self.a, self.b, self.c)

constant_object = myclass(1,2,3)
variable_object = myclass(*constant_object.tuple())
variable_object.a = 999

>>> constant_object.a
1
>>> variable_object.a
999

Usually (as others have suggested), you'd want to deepcopy. This creates a brand new object, with no ties to the object being copied. However, given that you are using only ints, deepcopy is overkill. You're better off doing a shallow copy. As a matter of fact, it might even be faster to call the class constructor on the parameters of the object you already have, seeing as these parameters are ints. This is why I suggested the above code.

Upvotes: 1

abarnert
abarnert

Reputation: 366103

Now I would like to create objects of this class, which would be constants and have pre-defined attribute values, which I could then assign to a variable/mutable object, thereby initializing this variable object's attributes to match the constant object,

Well, you can't have that. Assignment in Python doesn't initialize anything. It doesn't copy or create anything. All it does is give a new name to the existing value.

If you want to initialize an object, the way to do that in Python is to call the constructor.

So, with your existing code:

new_object = myclass(old_object.a, old_object.b, old_object.c)

If you look at most built-in and stdlib classes, it's a lot more convenient. For example:

a = set([1, 2, 3])
b = set(a)

How do they do that? Simple. Just define an __init__ method that can be called with an existing instance. (In the case of set, this comes for free, because a set can be initialized with any iterable, and sets are iterable.)

If you don't want to give up your existing design, you're going to need a pretty clumsy __init__, but it's at least doable. Maybe this:

_sentinel = object()
def __init__(myclass_or_a, b=_sentinel, c=_sentinel):
    if isinstance(a, myclass):
        self.a, self.b, self.c = myclass_or_a.a, myclass_or_a.b, myclass_or_a.c
    else:
        self.a, self.b, self.c = myclass_or_a, b, c

… plus some error handling to check that b is _sentinel in the first case and that it isn't in the other case.


So, however you do it:

constant_object = myclass(1,2,3)
variable_object = myclass(constant_object)
variable_object.a = 999

Upvotes: 1

jgritty
jgritty

Reputation: 11935

import copy

class myclass(object):
    def __init__(self,a,b,c):
        self.a = a
        self.b = b
        self.c = c

    def tuple(self):
        return (self.a, self.b, self.c)

constant_object = myclass(1,2,3)
variable_object = copy.deepcopy(constant_object)
variable_object.a = 999
print constant_object.a
print variable_object.a

Output:

1
999

Upvotes: 1

Related Questions