У меня есть класс, который является потомком декларативной базы SQLAlchemy.Мне нужно написать объект моста, который будет переводить между декларативной базой и другой системой, которую я использую, но я хочу, чтобы объект моста не знал точно, какие столбцы находятся в моей записи.В таком случае мне нужен способ составить список всех столбцов в записи, чтобы избежать необходимости поддерживать список атрибутов в двух только смутно связанных местах и минимизировать репликацию между тем.Это означает, что я мог бы создать атрибуты столбца, а затем вести отдельный список имен столбцов, но опять же, репликация является фактором - если бы я хотел изменить структуру этой вещи позже, мне пришлось бы изменить ее в обоих местах.
В таком случае я подумал о том, чтобы вставить определения столбцов в dict, а затем перебрать их, чтобы создать определения каждого столбца с помощью setattr, например:
for k,v in self.__column_dict.items():
setattr(self,k,
sqlalchemy.Column(v['column_type'],**v.get('opts',{})),
)
Теперь,вот в чем проблема: если я вставлю этот бит кода на уровне класса, self еще не определено, и я получаю ошибку (что имеет смысл).Если я вставлю это в __init__
, самоопределение будет определено, но декларативная база SQLAlchemy выдает ошибку, поскольку к моменту окончания определения класса первичный ключ в таблице отсутствует (что имеет смысл, поскольку эти атрибуты не будутустановить до времени выполнения).
Итак, как все говорят, как получить то, что я хочу, без использования eval, или использовать eval - мой единственный вариант, здесь?
EDIT:Я принял решение, приведенное ниже, но не использовал его на 100% (хотя оно помогло мне получить ответ).Вот что я в итоге сделал: (обратите внимание, что DeclarativeMeta является частью sqlalchemy.ext.declarative, того же пакета, что и Declarative_base)
class MyMeta(DeclarativeMeta):
def __new__(meta, classname, bases, dict_):
klass = type.__new__(meta, classname, bases, dict_)
if dict_.has_key('__classinit__'):
klass.__classinit__ = staticmethod(klass.__classinit__.im_func)
klass.__classinit__(klass, dict_)
return klass
Затем в моем производном классе
class DerivedClass(declarative_base()):
__tablename__ = 'yaddayadda'
__metaclass__ = MyMeta
def __classinit__(klass, dict_):
klass.__column_dict = <column dict here>
for k,v in klass.__column_dict.items():
setattr(klass,k,
<fancy column stuff>
)
...<rest of class definition>...