簡體   English   中英

我可以在__new__或__init__期間創建類屬性嗎?

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

我想做這樣的事情,但是到目前為止我還沒有取得太大的成功。 我想使每個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

描述符(例如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)

與類裝飾器語法具有相同的語義。

從技術上講,您需要一個元類:

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

您可以考慮使用__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