假设我有一个课程,我想制作很多类似的“属性风格”属性。例如:
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?
答案 0 :(得分:0)
采用描述符的想法并将其与元类混合,正如我在评论中提到的那样。
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"