Почему классы SQLAlchemy, наследующие от Base, не нуждаются в конструкторе?

С объектами SQLAlchemy, наследующими от Base класса, я могу передавать аргументы классу для переменных, которые не определены в конструкторе:

 from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, Sequence('user_id_seq'), primary_key=True) name = Column(String(50)) fullname = Column(String(50)) password = Column(String(12)) def __repr__(self): return "<User(name='%s', fullname='%s', password='%s')>" % ( self.name, self.fullname, self.password) ed_user = User(name='ed', fullname='Ed Jones', password='edspassword') 

конечно, если бы я попытался передать такие аргументы другому классу, чтобы установить переменные класса таким же образом, я бы получил ошибку:

 In [1]: class MyClass(object): ...: i = 2 ...: In [2]: instance = MyClass(i=9) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-2-6d3ec8445b00> in <module>() ----> 1 instance = MyClass(i=9) TypeError: object.__new__() takes no parameters 

Какая уловка – это SQLalchemy? Почему они просто не используют конструктор (т.е. метод __init__ )?

One Solution collect form web for “Почему классы SQLAlchemy, наследующие от Base, не нуждаются в конструкторе?”

Вы на самом деле задали здесь два вопроса.

Сначала вы спросили: «Какая трюк – это SQLAlchemy». Существует немного больше за кулисами, используя концепцию Metaclasses для динамического создания Base класса.

Но на самом деле все, что вам нужно знать, это то, что SQLAlchemy определяет конструктор (хотя и обходным путем) в классе Base который динамически устанавливает элементы. На самом деле это реализация этого метода (по крайней мере, поскольку он существует во время этого ответа):

 def _declarative_constructor(self, **kwargs): """A simple constructor that allows initialization from kwargs. Sets attributes on the constructed instance using the names and values in ``kwargs``. Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships. """ cls_ = type(self) for k in kwargs: if not hasattr(cls_, k): raise TypeError( "%r is an invalid keyword argument for %s" % (k, cls_.__name__)) setattr(self, k, kwargs[k]) 

В принципе, это динамическое определение аргументов ключевого слова и автоматическое определение атрибутов нового объекта. Вы можете представить, что Base класс выглядит следующим образом, хотя имейте в виду, что это на самом деле немного сложнее (вы можете прочитать код, чтобы узнать больше):

 class Base(object): def __init__(self, **kwargs): cls_ = type(self) for k in kwargs: if not hasattr(cls_, k): raise TypeError( "%r is an invalid keyword argument for %s" % (k, cls_.__name__)) setattr(self, k, kwargs[k]) 

Если вы создали вышеуказанный код, любой класс, который вы создаете, который наследует Base , автоматически получит возможность иметь атрибуты свойства автозаполнения, если атрибут уже определен в классе. Это связано с типичной объектно-ориентированной структурой наследования Python: если вы не определяете метод в объекте User , Python ищет метод, определенный в базовом классе (в данном случае метод Base ), и будет использовать это вместо , Это касается метода __init__ , как и любой другой метод.

Второй вопрос: «Почему они просто не используют конструктор (т.е. метод __init__ )?» Ну, как мы уже описали выше, они делают! Они устанавливают метод _declarative_constructor __init__ Base класса, эффективно устанавливая логику по умолчанию для построения объекта. Конечно, это только определяет значение по умолчанию; вы всегда можете переопределить это, если хотите …

 class User(Base): __tablename__ = 'users' id = Column(Integer, Sequence('user_id_seq'), primary_key=True) name = Column(String(50)) fullname = Column(String(50)) password = Column(String(12)) def __init__(self, name): self.name = name self.fullname = name self.password = generate_new_password() # The following will now work... ed_user = User('ed') mark_user = User(name='mark') # ...but this will not... problem_user = User(name='Error', fullname='Error M. McErrorson', password='w00t') 
  • SQLAlchemy создает динамические таблицы и столбцы
  • Игнорировать блокировку в базе данных MYSQL в запросе Sqlalchemy
  • В SQLAlchemy я могу создать Engine из существующего ODBC-соединения?
  • SQLAlchemy - сопоставление самореферентных отношений как одного для многих (декларативная форма)
  • Включить выполнение нескольких операторов во время выполнения через sqlalchemy
  • Запрос фильтра SQLAlchemy связанным объектом
  • метод итерации по определенным столбцам модели sqlalchemy?
  • Предотвратите касание db во время модульного тестирования с помощью SQLAlchemy
  • Python - лучший язык программирования в мире.