简体   繁体   中英

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?

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

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 int s, 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 int s. This is why I suggested the above code.

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 set s 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM