How to make an immutable instance

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Batista, Facundo

    How to make an immutable instance

    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:
    [color=blue][color=green][color=darkred]
    >>> import imm
    >>> c = C(4)
    >>> c.x[/color][/color][/color]
    4[color=blue][color=green][color=darkred]
    >>> c.x = 3[/color][/color][/color]

    Traceback (most recent call last):
    File "<pyshell#4 >", line 1, in -toplevel-
    c.x = 3
    AttributeError: can't set attribute[color=blue][color=green][color=darkred]
    >>> c.a = 3[/color][/color][/color]

    Traceback (most recent call last):
    File "<pyshell#5 >", line 1, in -toplevel-
    c.a = 3
    AttributeError: 'C' object has no attribute 'a'[color=blue][color=green][color=darkred]
    >>> hash(c)[/color][/color][/color]
    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.

  • Peter Otten

    #2
    Re: How to make an immutable instance

    Batista, Facundo wrote:
    [color=blue]
    > 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)[/color]
    [color=blue]
    > 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.[/color]

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

    An alternative would be to subclass tuple:
    [color=blue][color=green][color=darkred]
    >>> class C(tuple):[/color][/color][/color]
    .... def __new__(cls, x):
    .... return tuple.__new__(c ls, (x,))
    .... x = property(lambda self: self[0])
    ....[color=blue][color=green][color=darkred]
    >>> c = C(1)
    >>> c.x[/color][/color][/color]
    1

    Not necessarily better, as
    [color=blue][color=green][color=darkred]
    >>> isinstance(c, tuple)[/color][/color][/color]
    True

    and a Decimal pretending to be a sequence type may cause greater
    inconveniences than the "weak immutability" you currently have.
    [color=blue]
    > Thank you all![/color]

    Thank you for your work to further improve Python.

    Peter

    Comment

    • Leif K-Brooks

      #3
      Re: How to make an immutable instance

      Batista, Facundo wrote:[color=blue]
      > 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?[/color]

      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__(sel f, attr, value):
      if attr in self.__slots__ and not hasattr(self, attr):
      object.__setatt r__(self, attr, value)
      else:
      raise AttributeError, "This object is immutable."


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

      Comment

      • Aahz

        #4
        Re: How to make an immutable instance

        In article <2jem4iF10udstU 1@uni-berlin.de>,
        Leif K-Brooks <eurleif@ecritt ers.biz> wrote:[color=blue]
        >Batista, Facundo wrote:[color=green]
        >>
        >> 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?[/color]
        >
        > [...]
        >
        >But note that you can still use object.__setatt r__ directly to get
        >around it. I don't think there's a way to get true immutability in pure
        >Python.[/color]

        Correct. Remember that Python is a language for consenting adults; the
        only way to guarantee object immutability is to create a type in C.
        --
        Aahz (aahz@pythoncra ft.com) <*> http://www.pythoncraft.com/

        "Typing is cheap. Thinking is expensive." --Roy Smith, c.l.py

        Comment

        • Michael Hudson

          #5
          Re: How to make an immutable instance

          "Batista, Facundo" <FBatista@uniFO N.com.ar> writes:
          [color=blue]
          > I'm working on Decimal, and one of the PEP requests is Decimal to be
          > immutable.[/color]

          [...]
          [color=blue]
          > 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?[/color]

          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

          --
          I also feel it essential to note, [...], that Description Logics,
          non-Monotonic Logics, Default Logics and Circumscription Logics
          can all collectively go suck a cow. Thank you.
          -- http://advogato.org/person/Johnath/diary.html?start=4

          Comment

          Working...