Pregunta

I would like to create a class member that can be assigned a user-specified value by the constructor, but could not be changed afterwards. Is there a way to do this?

So far I have gotten the following code, which mostly works but is not "idiot proof".

def constantify(f):
    def fset(self, value):
        raise SyntaxError ('Not allowed to change value')
    def fget(self):
        return f(self)
    return property(fget, fset)

class dummy(object):
    def __init__(self,constval):
        self.iamvar = None
        self._CONST = constval

    @constantify
    def SOMECONST(self):
        return self._CONST


dum = dummy(42)
print 'Original Val:', dum.SOMECONST

this prints "Original Val: 42"

dum.SOMECONST = 24 

This gives the correct SyntaxError

But, enter an idiot,

dum._CONST = 0
print 'Current Val:', dum.SOMECONST

gives "Current Val: 0"

Is there a better idiot-proof way of achieving this?

Or is it the case that an class member that is initializable but remains const afterwards is somehow not a "pythonic" way? (I'm still a newbie learning the pythonic way) In that case, What would be a pythonic way of creating a class for which each instance is "configurable" at the time of instantiation only?

Kalpit

Update: I don't want to create a class for which all the members are immutable. I only want some members to be constant, and others variable at any time.

¿Fue útil?

Solución

The simplest way I could think of, is to override the __setattr__ and raise an Error whenever the particular attribute is set, like this

class dummy(object):
    def __init__(self, arg):
        super(dummy, self).__setattr__("data", arg)

    def __setattr__(self, name, value):
        if name == "data":
            raise AttributeError("Can't modify data")
        else:
            super(dummy, self).__setattr__(name, value)

a = dummy(5)
print a.data
# 5
a.data = "1"
# AttributeError: Can't modify data

Otros consejos

One nice thing about collections.namedtuple is that you can derive another class from an instance of it:

from collections import namedtuple

class Foo(namedtuple('Foo', ['a', 'b'])):
    def __new__(cls, a, b, *args, **kwargs):
        return super(Foo, cls).__new__(cls, a, b)

    def __init__(self, a, b, c):
        # a & b are immutable and handled by __new__
        self.c = c
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top