gpt4 book ai didi

python - 模型中的 SQLAlchemy 自定义本地属性

转载 作者:太空宇宙 更新时间:2023-11-03 13:19:43 25 4
gpt4 key购买 nike

我定义了一个简单的模型,并向类中添加了一些非 SQL 相关的属性。

如果属性是 int 或 string 类型,一切正常。但如果它是字典或列表类型,那么神奇的是,同一个列表将用于模型类的所有不同实例。

例子:

# Sample model class
class TestClass(Base):
# SQL Mappings
__tablename__ = 'test1'

pid = Column("id", Integer, primary_key=True)
name = Column('name', String)

# Non SQL related attributes
works_var = 0
works_not_var = []
# ...

在对检索到的 TestClass 实例进行查询之后的其他地方

my_test_class.works_not_var.append("testval1")
my_test_class2.works_not_var.append("testval2")

不知何故,两个附加值最终都在同一个列表中:

print id(my_test_class.works_not_var)
print id(my_test_class2.works_not.var)

ID 相同。但它适用于“works_var”。 ID 有不同。

最佳答案

这与 SQLAlchemy 绝对无关,是标准的 Python 行为。问题的原因与 Python 如何处理类型以及何时解析事物有关。考虑这个有趣的例子:

class A(object):
print "Hello"
print "A is now defined"
a = A()
print "I now have an instance of A"

这当然是完全没用的,但观察一下,当执行时,打印的顺序是:

Hello
A is now defined
I now have an instance of A

你有预料到吗?

简单的解决方案

# Sample model class
class TestClass(Base):
# SQL Mappings
__tablename__ = 'test1'

pid = Column("id", Integer, primary_key=True)
name = Column('name', String)
# ...

def __init__(self):
self.works_var = 0
self.works_not_var = []

经验法则:将默认参数放在 __init__ 而不是类级别。

说明

可能需要更详尽的解释:为什么会出现问题?我不会详细介绍 Python 通常如何处理变量。在 eevee 的 Python FAQ: Passing 中有一个简洁的解释文章。此外,这里有一个很好的解释:Other languages have "variables" .

有了这些知识和上面的例子,我们现在知道什么时候语句 works_not_var = [] 被执行:它被导入的那一刻(或者脚本是开始)。我们也知道为什么这是一个问题:像 list 这样的对象是可变的,当你改变它时 Python 不会移动它的“标签”:而是你创建了一个实例变量。更常见的是,这个问题在函数默认参数上被注意到(并且更容易解释)。考虑这个 SO 问题:“Least Astonishment” in Python: The Mutable Default Argument .它很好地解释了这是怎么来的。在一个简洁的例子中:

def f(a=[]):
if len(a) == 0:
print "Oh no, list is empty"
a.append(1)

f()
print "Function executed first time"
f()
print "Function executed second time"

输出:

Oh no, list is empty
Function executed first time
Function executed second time

列表是在解析它们时创建的,而不是执行时间。这可能会失败并产生愚蠢问题的另一个例子:

from datetime import datetime
from time import sleep

def f(time=datetime.now()):
print time

f()
sleep(1)
f()
f(datetime.now())

因此,您创建了一个函数来获取默认为当前时间的时间。好吧,没那么多。它默认为程序启动的时间,而不是当前时间。如果你运行它你会得到:

2013-08-20 16:14:29.037069
2013-08-20 16:14:29.037069
2013-08-20 16:14:30.038302

但是您会期望第二次和第三次在“第二”级别上几乎相等并且没有差异。问题又来了:默认参数datetime.now()是在函数解析时执行的,没有执行。

解决方案

为此还有一个简单的解决方案(尽管我可能会说我觉得它没有我想要的那么漂亮):

def f(now=None):
if now is None:
now = datetime.now()

我希望这个解释对您有所帮助。

关于python - 模型中的 SQLAlchemy 自定义本地属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18336135/

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