我可以在新建或初始化期间创建类属性吗?

2024-06-13 19:04:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我想做这样的事,但到目前为止我还没有成功。我想让每个attr都成为一个属性,它只在访问时计算_lazy_eval:

class Base(object):
    def __init__(self):
        for attr in self._myattrs:
            setattr(self, attr, property(lambda self: 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

#desired output:
#"foo"
#"bar"

**更新**

这也不起作用:

^{pr2}$

**更新2**

使用了__metaclass__解决方案,但却将其卡在Base.__new__中。它似乎需要一个定义更好的闭包--“prop()”,才能正确地形成属性:

class Base(object):
    def __new__(cls):
        def prop(x):
            return property(lambda self: self._lazy_eval(x))
        for attr in cls._myattrs:
            setattr(cls, attr, prop(attr))
        return object.__new__(cls)

#Actual output!  It works!
#foo
#bar

Tags: selfnewbasereturnobjectfoodefeval
3条回答

您可以通过

self.__class__.attr

描述符(例如property类型的实例)只有在对象中,而不是在实例对象中时才有意义。因此,您需要更改类,而不是实例,(在Python2.6或更高版本中)类修饰符非常方便:

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']

如果您坚持使用Python2.5或更早版本,decorator语法不适用于类,但是很容易获得相同的效果,只需使用不太漂亮的语法——将最后3行更改为:

^{pr2}$

它的语义与类decorator语法相同。在

从技术上讲,你需要一个元类:

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

相关问题 更多 >