Я пытаюсь преобразовать переменные класса в переменные экземпляра во время выполнения, аналогично тому, что происходит в ORM Django, где переменные класса различных типов преобразуются в переменные экземпляра одних и тех же типов во время выполнения.Как преобразовать переменные класса в переменные экземпляра в Python?
Я использую метакласс, чтобы собирать переменные класса определенных типов в список и затем устанавливать их как переменные экземпляра при создании экземпляра. Я попытался удалить исходные переменные класса, а также сохранить их, и я получаю разные результаты в обоих случаях, как нежелательные.
- Я создал простой объект Field, который использует _ получить _ и _ набора _ дескрипторов для преобразования значений в типы. Простая реализация поля - это текстовое поле, которое уникодирует значение на _ получает _.
- При создании класса метакласс собирает все атрибуты типа «Поле» в список
- Затем список полей устанавливается как класс _meta ['fields'].
- Когда класс создается в объект, эти _meta ['fields'] затем устанавливаются в объект. В одном случае исходный класс var удаляется перед началом работы.
- я тогда тест пути создания двух объектов, установив атрибут TextField один к какому-то тексту, ожидая _ получить _ и _ набор _ называться и как имеющие различные удобствами конфликтующих значений.
Когда переменная класса удаляется, устанавливая значение поля фактически не называют _ установить или _ получить _ и поле просто меняет тип на ул. Когда я не удаляю переменную класса, оба экземпляра экземпляра разделяют значения между ними.
Я разбавил свой код кодом ниже, который может быть сохранен в файл и запущен с python test.py
или импортирован в оболочку python. Установка DELETE_CLASS_VAR в True приведет к удалению переменных класса (для учета обоих тестовых случаев).
Очевидно, что у меня что-то отсутствует. Если это не сработает, я бы использовал регулярную переменную экземпляра, но мне очень понравилась модель Django (и я успешно прошел код Django), где переменные класса, установленные на модели, становятся ее экземплярами переменных с некоторой степенью типа и конкретные методы, установленные в них.
Спасибо!
# Set to True to delete class variables
DELETE_CLASS_VAR = False
class Field(object):
def __init__(self, *args, **kwargs):
self.value = None
self._args = args
self._kwargs = kwargs
def __get__(self, instance, owner):
print "__get__ called:", instance
return self.to_python()
def __set__(self, instance, value):
print "__set__ called:", instance, value
self.value = self.from_python(value)
def to_python(self):
return self.value
def from_python(self, value):
return value
class TextField(Field):
def to_python(self):
return unicode(self.value)
class ModelMetaClass(type):
def __new__(cls, name, bases, attrs):
print "Creating new class: %s" % name
obj = super(ModelMetaClass, cls).__new__(cls, name, bases, attrs)
print "class=", cls
_keys = attrs.keys()
_fields = []
for key in _keys:
if isinstance(attrs[key], Field):
_field = attrs.pop(key)
_fields.append({'name':key, 'value': _field })
setattr(obj, '_meta', {'fields': _fields})
print "-"*80
return obj
class Model(object):
__metaclass__ = ModelMetaClass
def __init__(self):
print "ROOT MODEL INIT", self._meta
print "-"*80
super(Model, self).__init__()
_metafields = self._meta.get('fields',[])
for _field in _metafields:
_f = _field['value']
if DELETE_CLASS_VAR and hasattr(self, _field['name']):
delattr(self.__class__, _field['name'])
setattr(self, _field['name'], _f.__class__(*_f._args, **_f._kwargs))
class BasicAdModel(Model):
def __init__(self):
super(BasicAdModel, self).__init__()
self._id = None
self.created_at = None
self.last_modified = None
class SpecialAdModel(BasicAdModel):
textfield = TextField()
def __init__(self):
super(SpecialAdModel, self).__init__()
print "INIT SPECIALAD", self._meta
print "-"*80
print "* creating two models, Ad1 and Ad2"
Ad1 = SpecialAdModel()
Ad2 = SpecialAdModel()
print "* Ad1 textfield attribute is", Ad1.textfield
print "* Setting Ad1 TextField instance to 'Text', expecting __set__ on Textfield to be called"
Ad1.textfield = "Text"
if DELETE_CLASS_VAR:
print "* If the class var was deleted on instantiation __get__ is not called here, and value is now str"
print "\tNew value is: ", Ad1.textfield
print "* Getting Ad2.textfield, expecting __get__ to be called and no value."
if DELETE_CLASS_VAR:
print "* If the class var was deleted - again __get__ is not called, attribute repalced with str"
print "\tAd2.textfield=", Ad2.textfield
print "* Setting Ad2 text field "
Ad2.textfield = "A different text"
if not DELETE_CLASS_VAR:
print "* When class var is not deleted, the two separate instances share the value later set on Ad2 "
print "\tAd2.textfield=",Ad2.textfield
print "\tAd1.textfield=", Ad1.textfield
Возможно, вы можете немного уточнить, чего вы пытаетесь достичь? Вы, похоже, хотите подражать поведению Django, но почему бы вам тогда не использовать, например. его класс «Свойство» для наследования? Кроме того, что обезвреживание обезьяны «_мета» экземпляра, как и вы, может привести к неожиданному поведению ... –
Я пытаюсь создать подобный тип модели для моделей Django, но специализируется на нашем приложении и использует MongoDb в качестве бэкэнд. Я знаю порт django-nonrel и брандмау mongodb, но мне не интересны большинство функций - просто нужна модель с некоторой базовой типизацией на полях, которые я могу использовать для разных целей (распространяются на специализированные модели и т. Д.). Конечным результатом является перенос кучи моделей на основе django и их перемещение от бэкэнда Postgres и в Mongo. Я могу сделать это, используя переменные экземпляра с тем же подходом, но надеялся, что этот подход будет первым. – Harel
Кроме того, фактические реализации полей в стороне, проблема, с которой я сталкиваюсь, заключается в преобразовании этих полей из исходных переменных класса в переменные экземпляра. – Harel