gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 21:31:52 25 4
gpt4 key购买 nike

使用从 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')

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

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__ 方法)?

最佳答案

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

首先,您问“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 类想象成如下所示,但请记住它实际上有点复杂(您可以阅读代码以了解更多信息):

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 方法设置为 Base 类的 __init__ 属性,有效地设置了对象构造的默认逻辑。当然,这只是定义了默认值;如果你想,你可以随时覆盖它......

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

关于python - 为什么从 Base 继承的 SQLAlchemy 类不需要构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20715035/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com