phistakis
phistakis

Reputation: 221

pythonic way of computing a value to a class object only once

I have a class where I need access to a computed value that can only be calculated per subclass. This computation is not cheap, and since there are many instantiations of the subclasses, I want to compute this value only once per subclass.

I can think of two solution which I don't really like:

Either the parent class will have a @classmethod start() which will compute the values. this enforces me to identify the precise location of the first instantiation of each class, so I've ruled this option out.

or, this code:

class A(object):
    @classmethod
    def _set_cls_attribute(cls):
        if hasattr(cls, 'big_attr'):
            return
        cls.big_attr = heavy_func(cls.VAL)

    def __init__(self):
        self._set_cls_attribute()

class B(A):
        VAL = 'b'

class C(A):
        VAL = 'c'


for _ in range(large_number):
        b = B()
        c = C()

I don't like using hasattr though... Is there anything better?

Upvotes: 1

Views: 205

Answers (2)

John La Rooy
John La Rooy

Reputation: 304147

A metaclass is a handy way to solve this

class A_meta(type):
    def __init__(cls, *args):
        type.__init__(cls, *args)
        if hasattr(cls, 'VAL'):
            cls.big_attr = heavy_func(cls.VAL)

class A(object):
    __metaclass__ = A_meta

class B(A):
        VAL = 'b'

class C(A):
        VAL = 'c'

Another way along the same lines as yours. This has the advantage of deferring the call to heavy_func until the attribute is first accessed.

class A(object):
    def __getattr__(self, attr):
        if attr == 'big_attr':
            self.__class__.big_attr = heavy_func(self.VAL)
        return object.__getattribute__(self, attr)

Upvotes: 1

deufeufeu
deufeufeu

Reputation: 1008

Without metaclasses or hasattr :

class A(object):
   @classmethod
   def attribute(cls):
       v = heavy_func(cls.VAL)
       cls.attribute = lambda k : v
       return v

Upvotes: 1

Related Questions