简体   繁体   English

我可以在__new__或__init__期间创建类属性吗?

[英]Can I create class properties during __new__ or __init__?

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: 我想使每个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"

** UPDATE ** **更新**

This doesn't work either: 这也不起作用:

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

** UPDATE 2 ** **更新2 **

Used the __metaclass__ solution, but stuck it in Base.__new__ instead. 使用__metaclass__解决方案,但将其停留在Base.__new__ It looks like it needed a better defined closure -- "prop()" -- to form the property correctly: 似乎需要更好地定义闭包-“ 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

Descriptors (such as instances of the property type) are only meaningful when they're held in the class object, not the instance object. 描述符(例如property类型的实例)仅在存放在对象中时才有意义,而在实例对象中时才有意义。 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: 因此,您需要更改类,而不是实例,并且(在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']

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: 如果您使用Python 2.5或更早版本,则装饰器语法不适用于类,但是很容易获得相同的效果,只需减少一些精巧的语法即可-将最后3行更改为:

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

which has the same semantics as the class decorator syntax. 与类装饰器语法具有相同的语义。

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

您可以通过__ class __ dict访问类属性

self.__class__.attr

You could consider using __getattr__() instead: 您可以考虑使用__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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM