Class property
Bengt Richter
bokr at oz.net
Fri Oct 14 22:31:57 EDT 2005
On Thu, 06 Oct 2005 16:09:22 +0200, Laszlo Zsolt Nagy <gandalf at designaproduct.biz> 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
More information about the Python-list
mailing list