【发布时间】:2016-01-09 10:34:07
【问题描述】:
我正在使用元类为这样的新类创建属性:
class Property(object):
def __init__(self, internal_name, type_, default_value):
self._internal_name = internal_name
self._type = type_
self._default_value = default_value
def generate_property(self):
def getter(object_):
return getattr(object_, self._internal_name)
def setter(object_, value):
if not isinstance(value, self._type):
raise TypeError("Expect type {0}, got {1}.".format(self._type, type(value)))
else:
setattr(object_, self._internal_name, value)
return property(getter, setter)
class AutoPropertyMeta(type):
def __new__(cls, name, bases, attributes):
for name, value in attributes.iteritems():
if isinstance(value, Property):
attributes[name] = value.generate_property()
return super(AutoPropertyMeta, cls).__new__(cls, name, bases, attributes)
这样我就可以写出这样的代码了:
class SomeClassWithALotAttributes(object):
__metaclass__ = AutoPropertyMeta
attribute_a = Property("_attribute_a", int, 0)
...
attribute_z = Property("_attribute_z", float, 1.0)
代替:
class SomeClassWithALotAttributes(object):
def __init__(self):
self._attribute_a = 0
...
self._attribute_z = 1.0
def get_attribute_a(self):
return self._attribute_a
def set_attribute_a(self, value):
if not isinstance(value, int):
raise TypeError("Expect type {0}, got {1}.".format(self._type, type(value))
else:
self._attribute_a = value
attribute_a = property(get_attribute_a, set_attribute_a)
...
如果你总是在获取属性值之前设置值,它会很好用,因为 AutoPropertyMeta 只生成 getter 和 setter 方法。实际实例属性是在您第一次设置值时创建的。所以我想知道是否有办法通过元类为类创建实例属性。
这是我现在正在使用的一种解决方法,但我一直想知道是否有更好的方法:
class Property(object):
def __init__(self, internal_name, type_, default_value):
self._internal_name = internal_name
self._type = type_
self._default_value = default_value
def generate_property(self):
def getter(object_):
return getattr(object_, self._internal_name)
def setter(object_, value):
if not isinstance(value, self._type):
raise TypeError("Expect type {0}, got {1}.".format(self._type, type(value)))
else:
setattr(object_, self._internal_name, value)
return property(getter, setter)
def generate_attribute(self, object_):
setattr(object_, self._internal_name, self._default_value)
class AutoPropertyMeta(type):
def __new__(cls, name, bases, attributes):
property_list = []
for name, value in attributes.iteritems():
if isinstance(value, Property):
attributes[name] = value.generate_property()
property_list.append(value)
attributes["_property_list"] = property_list
return super(AutoPropertyMeta, cls).__new__(cls, name, bases, attributes)
class AutoPropertyClass(object):
__metaclass__ = AutoPropertyMeta
def __init__(self):
for property_ in self._property_list:
property_.generate_attribute(self)
class SomeClassWithALotAttributes(AutoPropertyClass):
attribute_a = Property("_attribute_a", int, 0)
【问题讨论】:
-
不创建实例就无法创建实例属性。为什么不把代码放在 getter 中检查属性是否存在,如果不存在则返回默认值?
-
你可以提前给属性赋值,不是吗?
-
@BrenBarn 如果属性不存在,我曾经尝试在 getter 中创建属性。但是通过这种方式,我必须在每次调用 getter 时检查属性是否存在。所以我改变了我在后面的问题中发布的解决方法。
-
我不确定这是元类魔法的好用例。为什么你希望所有这些属性都是属性?真的只是为了强制进行类型检查吗?听起来你在这里有点与 python 战斗..
-
@kkpattern:这有什么大不了的?