我想做这样的事情,但到目前为止我还没有取得多大成功。我想让每个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"
**更新**
这也不起作用:
class Base(object):
def __new__(cls):
for attr in cls._myattrs:
setattr(cls, attr, property(lambda self: self._lazy_eval(attr)))
return object.__new__(cls)
#Actual output (it sets both .foo and .bar equal to "bar"??)
#bar
#bar
**更新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
答案 0 :(得分:5)
描述符(例如property
类型的实例)仅在它们保存在类对象中时才有意义,而不是实例对象。因此,您需要更改类,而不是实例,并且(在Python 2.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']
如果您遇到Python 2.5或更早版本,装饰器语法不适用于类,但很容易获得相同的效果,只需使用较少漂亮的语法 - 将最后3行更改为:
class Child(Base):
_myattrs = ['foo', 'bar']
Child = lazyclass(Child)
,它与类装饰器语法具有相同的语义。
答案 1 :(得分:1)
从技术上讲,你需要一个元类:
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
答案 2 :(得分:0)
您可以通过__ class __ dict
访问类属性self.__class__.attr
答案 3 :(得分:0)
您可以考虑使用__getattr__()
代替:
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