Overriding properties

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Nick Patavalis

    #1

    Overriding properties

    Why does the following print "0 0" instead of "0 1"? What is the
    canonical way to rewrite it in order to get what I obviously expect?

    class C(object):
    __val = 0
    def set_value(self, val):
    if val < 0 : self.__val = 0
    else : self.__val = val
    def get_value(self) :
    return self.__val
    value = property(get_va lue, set_value)

    class CC(C):
    def set_value(self, val):
    if val < 0: self.__val = 1
    else : self.__val = val

    c = C()
    cc = CC()
    c.value = -1
    cc.value = -1
    print c.value, cc.value

    Thanks in advance
    /npat
  • Leif K-Brooks

    #2
    Re: Overriding properties

    Nick Patavalis wrote:[color=blue]
    > Why does the following print "0 0" instead of "0 1"? What is the
    > canonical way to rewrite it in order to get what I obviously expect?
    >
    > class C(object):[/color]
    <snip>[color=blue]
    > value = property(get_va lue, set_value)
    >
    > class CC(C):
    > def set_value(self, val):[/color]
    <snip>[color=blue]
    > c.value = -1
    > cc.value = -1
    > print c.value, cc.value[/color]

    The problem is that the names get_value and set_value are evaluated only
    once: when class C is first defined. The property has no knowledge of
    (or interest in) the fact that a different function named set_value has
    been defined.

    There are several ways to fix it. The simplest would be to create a new
    property object in CC's definition:

    class CC(C):
    def set_value(self, val):
    if val < 0:
    self.__val = 1
    else:
    self.__val = val
    value = property(C.get_ value, set_value)

    But an easier, more flexible method would be to use a metaclass which
    automatically adds properties for specially-named methods. One example
    of such a metaclass is autoprop from Guido van Rossum's descrintro
    essay; see <URL:http://www.python.org/2.2.3/descrintro.html >.

    Comment

    • Kay Schluehr

      #3
      Re: Overriding properties - Javaesque property rant

      [color=blue]
      > There are several ways to fix it. The simplest would be to create a[/color]
      new[color=blue]
      > property object in CC's definition:
      >
      > class CC(C):
      > def set_value(self, val):
      > if val < 0:
      > self.__val = 1
      > else:
      > self.__val = val
      > value = property(C.get_ value, set_value)[/color]

      It won't fix because __val is defined as a class variable in C, but as
      an instance variable in CC. The set_value method creates a new __val. A
      typical Python pitfall. C.get_value would still return _C__val.
      [color=blue]
      > But an easier, more flexible method would be to use a metaclass which[/color]
      [color=blue]
      > automatically adds properties for specially-named methods. One[/color]
      example[color=blue]
      > of such a metaclass is autoprop from Guido van Rossum's descrintro
      > essay; see <URL:http://www.python.org/2.2.3/descrintro.html >.[/color]

      Yes, but i dislike it either. This powerfull metaclass approach
      obscures the property creation right in the place. And it supports the
      tendency to create fat frameworks. A few weeks ago i talked to someone
      who avoided propertys completely because they seemed to Javaesque to
      him. I first agreed and understood his ranting about this awkward
      get_bla, set_blubb stuff. Then I rembebered that the property()
      function is just a descriptor-creator and one can easily wrap around it
      for simplification.

      So i defined defprop()

      def defprop(name, default = None, modify=None, check=None, types=[]):

      name = "__"+name
      def get(obj):
      if not hasattr(obj,nam e):
      setattr(obj,nam e, default)
      return getattr(obj,nam e)

      def set(obj,value):
      if types:
      if not True in [isinstance(valu e,t) for t in types]:
      raise TypeError, "Can't assign %s to property
      %s."%(value,nam e[2:])
      if check:
      if not check(value):
      raise TypeError, "Can't assign %s to property
      %s."%(value,nam e[2:])
      if modify:
      setattr(obj,nam e,modify(value) )
      else:
      setattr(obj,nam e,value)

      return property(get,se t,None)


      I left out to define delete. It was for demonstration purposes only.
      Now define Your own classes:

      class X(object):
      a = defprop("a")
      b = defprop("b",typ es=(tuple,list) )
      c = defprop("c",che ck = lambda x:hasattr(x,"__ len__"))
      d = defprop("d",def ault=0)

      class XX(X):
      def set_d(val):
      if val<0:
      return 1
      return val

      d = defprop("d",def ault=0,modify=s et_d) # overwrite d

      It would be nice also to refuse the redundant naming a = defprop("a")
      and write
      a = defprop() instead. But it's actually not possible at the moment (
      or only with deep introspection ).

      Session on:
      [color=blue][color=green][color=darkred]
      >>> x = X()
      >>> x.d[/color][/color][/color]
      0[color=blue][color=green][color=darkred]
      >>> xx = XX()
      >>> xx.d[/color][/color][/color]
      0[color=blue][color=green][color=darkred]
      >>> xx.d = -1
      >>> xx.d[/color][/color][/color]
      1

      Ciao
      Kay

      Comment

      Working...