1

我正在使用 SQLAlchemy,我刚刚阅读了有关该__new__功能的信息。我还阅读了这里的其他帖子,__new__所以我知道它们的区别__init__、它们被调用的顺序、它们的目的以及对我来说主要信息是:用于__new__控制新实例的创建

所以考虑到这一点,当我使用 SQLAlchemy 并想要检索一个实例(如果它不存在则创建一个实例,例如检索一个用户对象,我通常这样做:

user = DBSession.query(User).filter(User.id==user_id).first()
if not user:
    user = User()

这将返回当前用户或给我一个新用户。现在有了我对魔法的新知识,我认为这样的事情可能是个好主意:

user = User(id=user_id)

在我的数据库类中,我会调用:

def __new__(cls, id=0):
    if id:
        user = DBSession.query(User).filter(User.id==id).first()
    if not id or not user:
        user = super(User, cls).__new__(cls, id=id)
    return user

现在这段代码只是一个草稿(例如缺少对 super 的调用),但它应该清楚地指出这个想法。

现在我的问题是:这是一个好习惯还是我应该避免这种做法?如果应该避免:为什么?

4

3 回答 3

2

根据您的问题和评论,我建议您不要这样做,因为您似乎没有任何理由这样做,而且您似乎不明白自己在做什么。

你说你会放一定的代码__new__。但在__new__什么?如果你有这个:

class User(Base):
    def __new__(cls, id=0):
        if id:
            user = DBSession.query(User).filter(User.id==id).first()
        if not user:
            user = User()
        return user

. . . 然后当你尝试创建一个User实例时,它__new__会尝试创建另一个实例,依此类推,导致无限递归。

使用user = User.__init__()解决不了任何问题。 __init__总是返回 None,所以你只是试图创建一个 None 对象。

适当的用例__new__是当您想要更改通过执行实例化类时返回的对象类型时SomeClass()。很少需要这样做。最常见的情况是当您想要创建一个模仿内置类型(例如 )的用户定义类时dict,但即使这样您也可能不需要这样做。

如果您的代码在没有覆盖的情况下工作__new__,请不要覆盖__new__. 仅当您有无法以其他方式解决的特定问题或任务时才覆盖它。

于 2012-08-26T21:17:28.870 回答
0

据我所见和理解,没有理由不将您的代码放入__init__而不是__new__. 只有几个非常有限但有效的用例__new__,您应该真正知道自己在做什么。因此,除非您有充分的理由,否则请坚持使用__init__.

于 2012-08-26T20:42:30.503 回答
0

第一个示例(检查返回值)和第二个示例(立即使用构造函数)之间有一个非常明显的区别;那个区别是自由变量:DBSession.

在某些情况下,这种差异并不有趣。如果您仅将 sqlalchemy 映射对象用于数据库持久性;然后仅在sqlalchemy.orm.scopedsession允许的上下文中(每个线程恰好一个会话)。那么差异不是很有趣。

我发现这两种情况都成立是不寻常的,而且通常都不成立。

通过这样做,您可以防止对象在数据库持久性上下文之外发挥作用。通过断开模型与数据库的连接,您的应用程序可以回答诸如“如果该对象具有此属性怎么办?”之类的问题。除了诸如“这个对象有这个属性吗?”之类的问题。这就是为什么我们将数据库值映射为 python 对象的关键,这样它们就可以有有趣的行为,而不是仅仅作为dict属性包的 s。

例如,除了使用常规的数据库持久登录;您可能允许用户使用 OAuth 之类的方式登录您的网站。尽管您不需要将用户名和密码保存到数据库中,但您仍然需要创建User对象以使应用程序的其余部分正常工作(以便用户的头像出现在模板中)。

默认情况下隐式访问特定数据库上下文的另一个问题通常是一个坏主意。随着应用程序的增长,管理数据库方式的需求变得更加复杂。对象可以跨多个数据库主机进行分区;您可能在同一个线程中管理多个并发事务;出于缓存性能原因,您可能希望重用特定会话。sqlalchemySession类的存在是为了解决所有这些特性;明确地管理它们,即使您只是使用最常见的模式;使处理偶尔的变化变得更加容易。

Web 应用程序中一个非常常见的例子是启动代码。有时,在应用程序准备好处理任何请求之前,需要从数据库中提取一些关键数据;但是既然没有请求服务,那么数据库连接是从哪里来的呢?启动完成后如何摆脱它?这些问题通常与明确管理的会话无关。

于 2012-08-26T21:04:20.370 回答