我可以在 __new__ 或 __init__ 中创建类属性吗?
我想做类似的事情,但到目前为止还没有成功。我希望每个属性在被访问时才计算一次 _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
4 个回答
1
你可以通过 __ class __ dict 来访问类的属性。
self.__class__.attr
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 或更早的版本,类装饰器的语法就不适用了,但你仍然可以用其他简单的方法达到同样的效果,只是语法看起来没那么炫酷——把最后三行改成:
class Child(Base):
_myattrs = ['foo', 'bar']
Child = lazyclass(Child)
这样做的效果和类装饰器的语法是一样的。
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