Can I create class properties during __new__ or __init__?

前端 未结 4 1043
忘了有多久
忘了有多久 2021-01-18 23:52

I want to do something like this, but I haven\'t had much success so far. I would like to make each attr a property that computes _lazy_eval only when accessed:

<         


        
相关标签:
4条回答
  • 2021-01-19 00:10

    Technically you want a metaclass:

    class LazyMeta(type):
        def __init__(cls, name, bases, attr):
            super(LazyMeta, cls).__init__(name, bases, attr)
            def prop( x ):
                return property(lambda self: self._lazy_eval(x))
            for x in attr['lazyattrs']:
                setattr(cls, x, prop(x))
    
    class Base(object):
        __metaclass__ = LazyMeta
        lazyattrs = []
        def _lazy_eval(self, attr):
            #Do complex stuff here
            return attr
    
    class Child(Base):
        lazyattrs = ['foo', 'bar']
    
    me = Child()
    
    print me.foo
    print me.bar
    
    0 讨论(0)
  • 2021-01-19 00:17

    You can access class attributes through the __ class __ dict

    self.__class__.attr
    
    0 讨论(0)
  • 2021-01-19 00:21

    Descriptors (such as instances of the property type) are only meaningful when they're held in the class object, not the instance object. So, you need to change the class, not the instance, and (in Python 2.6 or better) a class decorator is very handy for that purpose:

    class Base(object):
        def _lazy_eval(self, attr):
            #Do complex stuff here
            return attr
    
    def lazyclass(cls):
        for attr in cls._myattrs:
            setattr(cls, attr, property(lambda self: self._lazy_eval(attr)))
        return cls
    
    @lazyclass
    class Child(Base):
        _myattrs = ['foo', 'bar']
    

    If you're stuck with Python 2.5 or earlier, the decorator syntax doesn't apply to classes, but it's easy to get the same effect, just with less nifty syntax -- change the last 3 rows to:

    class Child(Base):
        _myattrs = ['foo', 'bar']
    Child = lazyclass(Child)
    

    which has the same semantics as the class decorator syntax.

    0 讨论(0)
  • 2021-01-19 00:31

    You could consider using __getattr__() instead:

    class Base(object):
        def __getattr__(self, attr):
            if attr not in self._myattrs:
                raise AttributeError
            return self._lazy_eval(attr)
    
        def _lazy_eval(self, attr):
            #Do complex stuff here
            return attr
    
    
    class Child(Base):
        _myattrs = ['foo', 'bar']
    
    me = Child()
    print me.foo
    print me.bar
    
    0 讨论(0)
提交回复
热议问题