【问题标题】:Should I use a descriptor class or a property factory? [closed]我应该使用描述符类还是属性工厂? [关闭]
【发布时间】:2014-06-26 01:26:08
【问题描述】:

假设我有一个类,我想做很多类似的“属性样式”属性。例如:

class Foo(object):
    @property
    def foo(self):
        return self._foo

    @foo.setter
    def foo(self, val):
        self.update()
        self._foo = val

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, val):
        self.update()
        self._bar = val

    @property
    def baz(self):
        return self._baz

    @baz.setter
    def baz(self, val):
        self.update()
        self._baz = val

    def update(self):
        print "Updating..."

显然这里有很多重复,最好把它排除在外。一种方法是创建一个返回属性的函数:

def create_property(var):
    def _setter(self, val):
        self.update()
        setattr(self, '_' + var, val)

    def _getter(self):
        return getattr(self, '_' + var)

    return property(_getter, _setter)

class Foo(object):
    foo = create_property("foo")
    bar = create_property("bar")
    baz = create_property("baz")

    def update(self):
        print "Updating..."

或者我可以写一个描述符类:

class UpdateOnChange(object):
    def __init__(self):
        self.data = WeakKeyDictionary()

    def __get__(self, instance, owner):
        try:
            return self.data[instance]
        except KeyError:
            raise AttributeError("attribute not set")

    def __set__(self, instance, value):
        instance.update()
        self.data[instance] = value

class Foo(object):
    foo = UpdateOnChange()
    bar = UpdateOnChange()
    baz = UpdateOnChange()

    def update(self):
        print "Updating"

哪个是最好的/最快的/最 Pythonic 的?

【问题讨论】:

  • 描述符正是为此而存在的。所以,在我看来,你应该使用描述符。我故意将其斜体以强调这主要是基于意见的。投票搁置,主要基于意见
  • 我也推荐装饰器。虽然如果你将它与元类结合起来,你可以自动获取类变量的名称来构造描述符,从而消除对 self.data 字典的需要。对于内存和性能开销而言,这会稍微好一些,但可能更重要的是,您永远不必在所指对象死亡的情况下处理关键冲突或奇怪行为。

标签: python properties descriptor


【解决方案1】:

如我在 cmets 中提到的,采用描述符的想法并将其与元类混合。

class UpdateOnChange(object):
    def __init__(self, name):
        self.name = name
        self._name = '_' + name

    def __get__(self, instance, owner):
        try:
            return getattr(instance, self._name)
        except AttributeError:
            raise AttributeError('%s has no attribute %s.' % (instance, self.name))

    def __set__(self, instance, value):
        # Assume first assignment is initialization and does not require update.
        if not hasattr(instance, self._name):
            setattr(instance, self._name, value)
        else:
            instance.update()
            setattr(instance, self._name, value)

class UpdateOnChangeMeta(type):

     def __new__(cls, name, bases, attrs):
         for attr_name in attrs:
             if attrs[attr_name] == UpdateOnChange:
                 attrs[attr_name] = UpdateOnChange(attr_name)
         return type.__new__(cls, name, bases, attrs)

class Foo(object):

    __metaclass__ = UpdateOnChangeMeta
    foo = UpdateOnChange
    bar = UpdateOnChange
    baz = UpdateOnChange

    def update(self):
        print "Updating"

【讨论】:

    猜你喜欢
    • 2016-08-03
    • 1970-01-01
    • 1970-01-01
    • 2012-06-20
    • 2013-05-23
    • 2013-02-05
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多