On Thu, 06 Oct 2005 16:09:22 +0200, Laszlo Zsolt Nagy <[EMAIL PROTECTED]> wrote:
>Peter Otten wrote: > >>Laszlo Zsolt Nagy wrote: >> >> >> >>>I was trying for a while, but I could not implement a 'classproperty' >>>function. Is it possible at all? >>> >>> >> >>You could define a "normal" property in the metaclass: >> >> >The only way I could do this is: > >class MyXMetaClass(type): > _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__,value) > 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: But it can install a property that can. > >class A(object): > cnt = 0 > a_cnt = 0 > ratio = a_class_property_that_returns_the_cnt_per_a_cnt_ratio() # ???? > def __init__(self): > A.cnt += 1 > if self.__class__ is A: > A.a_cnt += 1 > >Any ideas? > >>> 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__(type): ... 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... >>> class B(A): pass ... >>> A.ratio Getting ratio... Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 11, in ratio ZeroDivisionError: float division Oops ;-) >>> A.cnt, A.a_cnt (0, 0) >>> b=B() >>> A.cnt, A.a_cnt (1, 0) >>> A.ratio Getting ratio... 0.0 >>> a=A() >>> A.ratio Getting ratio... 0.5 >>> a=A() >>> A.ratio Getting ratio... 0.66666666666666663 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... >>> b2=B() >>> B.ratio Getting ratio... 0.5 >>> b3=B() >>> B.ratio Getting ratio... 0.40000000000000002 Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list