SQLAlchemy类为什么不需要从Base继承构造函数?

2024-04-20 00:39:50 发布

您现在位置:Python中文网/ 问答频道 /正文

对于继承自Base类的SQLAlchemy对象,我可以将参数传递给未在构造函数中定义的变量的类:

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')

当然,如果我试图将这样的参数传递给另一个类,以同样的方式设置类变量,我会得到一个错误:

^{pr2}$

SQLalchemy在搞什么鬼把戏?他们为什么不使用构造函数(即__init__方法)?在


Tags: 对象nameselfidbasestringsqlalchemycolumn
1条回答
网友
1楼 · 发布于 2024-04-20 00:39:50

你实际上问了两个问题。在

首先,你问“SQLAlchemy在搞什么鬼把戏”。在幕后还有一些事情要做,使用一个名为Metaclasses的概念来动态创建Base类。在

但实际上,您只需要知道SQLAlchemy是在动态设置元素的Base类中定义一个构造函数(尽管是迂回的)。Here实际上是该方法的实现(至少在回答这个问题时它是存在的):

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])

基本上,这是dynamically determining the keyword arguments,并自动设置新对象的属性。您可以将Base类想象为如下所示,但请记住它实际上要复杂一些(您可以阅读代码以了解更多信息):

^{pr2}$

如果您创建了上面的代码,您创建的继承自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')

相关问题 更多 >