How to make an immutable instance

B

Batista, Facundo

I'm working on Decimal, and one of the PEP requests is Decimal to be
immutable.

The closer I got to that is (in short):

class C(object):

__slots__ = ('__x',)

def __init__(self, value):
self.__x = value

def getx(self):
return self.__x

x = property(getx)

This way, you can not modify the instance:

Traceback (most recent call last):
File "<pyshell#4>", line 1, in -toplevel-
c.x = 3
AttributeError: can't set attribute
Traceback (most recent call last):
File "<pyshell#5>", line 1, in -toplevel-
c.a = 3
AttributeError: 'C' object has no attribute 'a'10777424


The problem is that you actually could, if you take the effort, to rebind
the __x name.

So, if you use this "immutable" class in a dict, and then you (on purpose)
modify it, you'll have different hashes.

Said that, how safer is this approach? Is there a better way?

Thank you all!

.. Facundo





.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . .
.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . .
.. . . . . . . . . . . . . . .
ADVERTENCIA

La información contenida en este mensaje y cualquier archivo anexo al mismo,
son para uso exclusivo del destinatario y pueden contener información
confidencial o propietaria, cuya divulgación es sancionada por la ley.

Si Ud. No es uno de los destinatarios consignados o la persona responsable
de hacer llegar este mensaje a los destinatarios consignados, no está
autorizado a divulgar, copiar, distribuir o retener información (o parte de
ella) contenida en este mensaje. Por favor notifíquenos respondiendo al
remitente, borre el mensaje original y borre las copias (impresas o grabadas
en cualquier medio magnético) que pueda haber realizado del mismo.

Todas las opiniones contenidas en este mail son propias del autor del
mensaje y no necesariamente coinciden con las de Telefónica Comunicaciones
Personales S.A. o alguna empresa asociada.

Los mensajes electrónicos pueden ser alterados, motivo por el cual
Telefónica Comunicaciones Personales S.A. no aceptará ninguna obligación
cualquiera sea el resultante de este mensaje.

Muchas Gracias.
 
P

Peter Otten

I'm working on Decimal, and one of the PEP requests is Decimal to be
immutable.

The closer I got to that is (in short):

class C(object):

__slots__ = ('__x',)

def __init__(self, value):
self.__x = value

def getx(self):
return self.__x

x = property(getx)
The problem is that you actually could, if you take the effort, to rebind
the __x name.

So, if you use this "immutable" class in a dict, and then you (on purpose)
modify it, you'll have different hashes.

I don't think this will be a problem in practice. If you are determined,
there are easier ways to break your program :)
Said that, how safer is this approach? Is there a better way?

An alternative would be to subclass tuple:
.... def __new__(cls, x):
.... return tuple.__new__(cls, (x,))
.... x = property(lambda self: self[0])
....1

Not necessarily better, as
True

and a Decimal pretending to be a sequence type may cause greater
inconveniences than the "weak immutability" you currently have.
Thank you all!

Thank you for your work to further improve Python.

Peter
 
L

Leif K-Brooks

So, if you use this "immutable" class in a dict, and then you (on purpose)
modify it, you'll have different hashes.

Said that, how safer is this approach? Is there a better way?

The best I know of is this:


class Foo(object):
__slots__ = ('x',)

# __new__ is used instead of __init__ so that no one can call
# __new__ directly and change the value later.
def __new__(cls, value):
self = object.__new__(cls)
self.x = value
return self

def __setattr__(self, attr, value):
if attr in self.__slots__ and not hasattr(self, attr):
object.__setattr__(self, attr, value)
else:
raise AttributeError, "This object is immutable."


But note that you can still use object.__setattr__ directly to get
around it. I don't think there's a way to get true immutability in pure
Python.
 
A

Aahz

So, if you use this "immutable" class in a dict, and then you (on purpose)
modify it, you'll have different hashes.

Said that, how safer is this approach? Is there a better way?

[...]

But note that you can still use object.__setattr__ directly to get
around it. I don't think there's a way to get true immutability in pure
Python.

Correct. Remember that Python is a language for consenting adults; the
only way to guarantee object immutability is to create a type in C.
 
M

Michael Hudson

Batista said:
I'm working on Decimal, and one of the PEP requests is Decimal to be
immutable.
[...]

So, if you use this "immutable" class in a dict, and then you (on purpose)
modify it, you'll have different hashes.

Said that, how safer is this approach? Is there a better way?

I'd say it's safe enough. It's going to be impossible to guard
against all malicious code, so you should aim to prevent accidents.

Cheers,
mwh
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top