Я использую метакласса создать свойство для новых классов, как это:Python: Как создать атрибут экземпляра метакласса?
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
вы можете назначить значение по умолчанию для атрибута раньше времени, нет? – HuStmpHrrr
@BrenBarn Я однажды попытался создать атрибут в getter, если атрибут не существует. Но таким образом мне придется проверять, существует ли атрибут каждый раз, когда вызывается получатель. Поэтому я перешел к обходному решению, которое я опубликовал в последнем вопросе. – kkpattern