Class property (was: Class methods)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Laszlo Zsolt Nagy

    #1

    Class property (was: Class methods)

    Hughes, Chad O wrote:
    [color=blue]
    > Is there any way to create a class method? I can create a class
    > variable like this:
    >[/color]
    Hmm, seeing this post, I have decided to implement a 'classproperty'
    descriptor.
    But I could not. This is what I imagined:

    class A(object):
    _x = 0
    @classmethod
    def get_x(cls):
    print "Getting x..."
    return cls._x
    @classmethod
    def set_x(cls,value ):
    print "Setting x..."
    cls._x = value
    x = classproperty(g et_x,set_x)

    Usage example:
    [color=blue][color=green][color=darkred]
    >>>print A.x[/color][/color][/color]
    Getting x
    0[color=blue][color=green][color=darkred]
    >>>A.x = 8[/color][/color][/color]
    Setting x[color=blue][color=green][color=darkred]
    >>>print A.x[/color][/color][/color]
    Getting x
    8

    I was trying for a while, but I could not implement a 'classproperty'
    function. Is it possible at all?
    Thanks,

    Les




  • Peter Otten

    #2
    Re: Class property (was: Class methods)

    Laszlo Zsolt Nagy wrote:
    [color=blue]
    > I was trying for a while, but I could not implement a 'classproperty'
    > function. Is it possible at all?[/color]

    You could define a "normal" property in the metaclass:
    [color=blue][color=green][color=darkred]
    >>>>> class A:[/color][/color][/color]
    .... class __metaclass__(t ype):
    .... @property
    .... def clsprp(cls): return 42
    ....[color=blue][color=green][color=darkred]
    >>> A.clsprp[/color][/color][/color]
    42

    Peter

    Comment

    • Laszlo Zsolt Nagy

      #3
      Re: Class property

      Peter Otten wrote:
      [color=blue]
      >Laszlo Zsolt Nagy wrote:
      >
      >
      >[color=green]
      >>I was trying for a while, but I could not implement a 'classproperty'
      >>function. Is it possible at all?
      >>
      >>[/color]
      >
      >You could define a "normal" property in the metaclass:
      >
      >[/color]
      The only way I could do this is:

      class MyXMetaClass(ty pe):
      _x = 0
      def get_x(cls):
      print "Getting x"
      return cls._x
      def set_x(cls,value ):
      cls._x = value
      print "Set %s.x to %s" % (cls.__name__,v alue)
      x = property(get_x, set_x)

      class A(object):
      __metaclass__ = MyXMetaClass

      print A.x
      A.x = 8


      Results in:

      Getting x
      0
      Set A.x to 8

      But of course this is bad because the class attribute is not stored in
      the class. I feel it should be.
      Suppose we want to create a class property, and a class attribute; and
      we would like the property get/set methods to use the values of the
      class attributes.
      A real example would be a class that keeps track of its direct and
      subclassed instances:

      class A(object):
      cnt = 0
      a_cnt = 0
      def __init__(self):
      A.cnt += 1
      if self.__class__ is A:
      A.a_cnt += 1

      class B(A):
      pass

      print A.cnt,A.a_cnt # 0,0
      b = B()
      print A.cnt,A.a_cnt # 1,0
      a = A()
      print A.cnt,A.a_cnt # 2,1

      But then, I may want to create read-only class property that returns the
      cnt/a_cnt ratio.
      This now cannot be implemented with a metaclass, because the metaclass
      cannot operate on the class attributes:

      class A(object):
      cnt = 0
      a_cnt = 0
      ratio = a_class_propert y_that_returns_ the_cnt_per_a_c nt_ratio() # ????
      def __init__(self):
      A.cnt += 1
      if self.__class__ is A:
      A.a_cnt += 1

      Any ideas?

      Les



      Comment

      • Steven Bethard

        #4
        Re: Class property

        Laszlo Zsolt Nagy wrote:[color=blue]
        > class A(object):
        > cnt = 0
        > a_cnt = 0
        > def __init__(self):
        > A.cnt += 1
        > if self.__class__ is A:
        > A.a_cnt += 1
        > class B(A):
        > pass
        > print A.cnt,A.a_cnt # 0,0
        > b = B()
        > print A.cnt,A.a_cnt # 1,0
        > a = A()
        > print A.cnt,A.a_cnt # 2,1
        >
        > But then, I may want to create read-only class property that returns the
        > cnt/a_cnt ratio.
        > This now cannot be implemented with a metaclass, because the metaclass
        > cannot operate on the class attributes:[/color]

        Huh? Every function in the metaclass takes the class object as the
        first parameter. So they can all operate on the class attributes:

        py> class A(object):
        .... cnt = 0
        .... a_cnt = 0
        .... def __init__(self):
        .... A.cnt += 1
        .... if self.__class__ is A:
        .... A.a_cnt += 1
        .... class __metaclass__(t ype):
        .... @property
        .... def ratio(cls):
        .... return cls.a_cnt/float(cls.cnt)
        ....
        py> class B(A):
        .... pass
        ....
        py> A.cnt, A.a_cnt
        (0, 0)
        py> A.ratio
        Traceback (most recent call last):
        File "<interacti ve input>", line 1, in ?
        File "<interacti ve input>", line 11, in ratio
        ZeroDivisionErr or: float division
        py> b = B()
        py> A.cnt, A.a_cnt, A.ratio
        (1, 0, 0.0)
        py> a = A()
        py> A.cnt, A.a_cnt, A.ratio
        (2, 1, 0.5)

        STeVe

        Comment

        • Bengt Richter

          #5
          Re: Class property (was: Class methods)

          On Thu, 06 Oct 2005 11:05:10 +0200, Laszlo Zsolt Nagy <gandalf@design aproduct.biz> wrote:
          [color=blue]
          >Hughes, Chad O wrote:
          >[color=green]
          >> Is there any way to create a class method? I can create a class
          >> variable like this:
          >>[/color]
          >Hmm, seeing this post, I have decided to implement a 'classproperty'
          >descriptor.
          >But I could not. This is what I imagined:
          >
          >class A(object):
          > _x = 0
          > @classmethod
          > def get_x(cls):
          > print "Getting x..."
          > return cls._x
          > @classmethod
          > def set_x(cls,value ):
          > print "Setting x..."
          > cls._x = value
          > x = classproperty(g et_x,set_x)
          >
          >Usage example:
          >[color=green][color=darkred]
          > >>>print A.x[/color][/color]
          >Getting x
          >0[color=green][color=darkred]
          > >>>A.x = 8[/color][/color]
          >Setting x[color=green][color=darkred]
          > >>>print A.x[/color][/color]
          >Getting x
          >8
          >
          >I was trying for a while, but I could not implement a 'classproperty'
          >function. Is it possible at all?
          >Thanks,
          >
          > Les
          >[/color]
          Using Peter's advice (not tested beyond what you see):
          [color=blue][color=green][color=darkred]
          >>> class A(object):[/color][/color][/color]
          ... _x = 0
          ... class __metaclass__(t ype):
          ... def get_x(cls):
          ... print "Getting x..."
          ... return cls._x
          ... def set_x(cls,value ):
          ... print "Setting x..."
          ... cls._x = value
          ... x = property(get_x, set_x)
          ...[color=blue][color=green][color=darkred]
          >>> A.x[/color][/color][/color]
          Getting x...
          0[color=blue][color=green][color=darkred]
          >>> A.x = 8[/color][/color][/color]
          Setting x...[color=blue][color=green][color=darkred]
          >>> A.x[/color][/color][/color]
          Getting x...
          8[color=blue][color=green][color=darkred]
          >>> vars(A).items()[/color][/color][/color]
          [('__module__', '__main__'), ('__metaclass__ ', <class '__main__.__met aclass__'>), ('_x', 8), ('_
          _dict__', <attribute '__dict__' of 'A' objects>), ('__weakref__', <attribute '__weakref__' of 'A
          ' objects>), ('__doc__', None)][color=blue][color=green][color=darkred]
          >>> A._x[/color][/color][/color]
          8[color=blue][color=green][color=darkred]
          >>> vars(A).keys()[/color][/color][/color]
          ['__module__', '__metaclass__' , '_x', '__dict__', '__weakref__', '__doc__']

          Regards,
          Bengt Richter

          Comment

          • Bengt Richter

            #6
            Re: Class property

            On Thu, 06 Oct 2005 16:09:22 +0200, Laszlo Zsolt Nagy <gandalf@design aproduct.biz> wrote:
            [color=blue]
            >Peter Otten wrote:
            >[color=green]
            >>Laszlo Zsolt Nagy wrote:
            >>
            >>
            >>[color=darkred]
            >>>I was trying for a while, but I could not implement a 'classproperty'
            >>>function. Is it possible at all?
            >>>
            >>>[/color]
            >>
            >>You could define a "normal" property in the metaclass:
            >>
            >>[/color]
            >The only way I could do this is:
            >
            >class MyXMetaClass(ty pe):
            > _x = 0
            > def get_x(cls):
            > print "Getting x"
            > return cls._x
            > def set_x(cls,value ):
            > cls._x = value
            > print "Set %s.x to %s" % (cls.__name__,v alue)
            > x = property(get_x, set_x)
            >
            >class A(object):
            > __metaclass__ = MyXMetaClass
            >
            >print A.x
            >A.x = 8
            >
            >
            >Results in:
            >
            >Getting x
            >0
            >Set A.x to 8
            >
            >But of course this is bad because the class attribute is not stored in
            >the class. I feel it should be.
            >Suppose we want to create a class property, and a class attribute; and
            >we would like the property get/set methods to use the values of the
            >class attributes.
            >A real example would be a class that keeps track of its direct and
            >subclassed instances:
            >
            >class A(object):
            > cnt = 0
            > a_cnt = 0
            > def __init__(self):
            > A.cnt += 1
            > if self.__class__ is A:
            > A.a_cnt += 1
            >
            >class B(A):
            > pass
            >
            >print A.cnt,A.a_cnt # 0,0
            >b = B()
            >print A.cnt,A.a_cnt # 1,0
            >a = A()
            >print A.cnt,A.a_cnt # 2,1
            >
            >But then, I may want to create read-only class property that returns the
            >cnt/a_cnt ratio.
            >This now cannot be implemented with a metaclass, because the metaclass
            >cannot operate on the class attributes:[/color]
            But it can install a property that can.[color=blue]
            >
            >class A(object):
            > cnt = 0
            > a_cnt = 0
            > ratio = a_class_propert y_that_returns_ the_cnt_per_a_c nt_ratio() # ????
            > def __init__(self):
            > A.cnt += 1
            > if self.__class__ is A:
            > A.a_cnt += 1
            >
            >Any ideas?
            >[/color]
            [color=blue][color=green][color=darkred]
            >>> class A(object):[/color][/color][/color]
            ... cnt = 0
            ... a_cnt = 0
            ... def __init__(self):
            ... A.cnt += 1
            ... if self.__class__ is A:
            ... A.a_cnt += 1
            ... class __metaclass__(t ype):
            ... def ratio(cls):
            ... print "Getting ratio..."
            ... return float(cls.a_cnt )/cls.cnt #
            ... ratio = property(ratio)
            ...
            I inverted your ratio to lessen the probability if zero division...
            [color=blue][color=green][color=darkred]
            >>> class B(A): pass[/color][/color][/color]
            ...[color=blue][color=green][color=darkred]
            >>> A.ratio[/color][/color][/color]
            Getting ratio...
            Traceback (most recent call last):
            File "<stdin>", line 1, in ?
            File "<stdin>", line 11, in ratio
            ZeroDivisionErr or: float division

            Oops ;-)
            [color=blue][color=green][color=darkred]
            >>> A.cnt, A.a_cnt[/color][/color][/color]
            (0, 0)[color=blue][color=green][color=darkred]
            >>> b=B()
            >>> A.cnt, A.a_cnt[/color][/color][/color]
            (1, 0)[color=blue][color=green][color=darkred]
            >>> A.ratio[/color][/color][/color]
            Getting ratio...
            0.0[color=blue][color=green][color=darkred]
            >>> a=A()
            >>> A.ratio[/color][/color][/color]
            Getting ratio...
            0.5
            [color=blue][color=green][color=darkred]
            >>> a=A()
            >>> A.ratio[/color][/color][/color]
            Getting ratio...
            0.6666666666666 6663

            The old instance is no longer bound, so should it still be counted as it is?
            You might want to check how to use weak references if not...
            [color=blue][color=green][color=darkred]
            >>> b2=B()
            >>> B.ratio[/color][/color][/color]
            Getting ratio...
            0.5[color=blue][color=green][color=darkred]
            >>> b3=B()
            >>> B.ratio[/color][/color][/color]
            Getting ratio...
            0.4000000000000 0002

            Regards,
            Bengt Richter

            Comment

            Working...