听起来您想序列化 ScriptA 的结果,将其保存在某个文件或数据库中,然后让 ScriptB 读取这些结果(可能还修改文件或更新数据库条目以表明这些结果现在已被处理)。
要完成这项工作,您需要让 ScriptA 和 ScriptB 就数据的位置和格式达成一致……并且您可能希望实现某种锁定以确保 ScriptB 不会以损坏的输入告终恰好在 ScriptA 写入或更新数据的同时运行(相反,ScriptA 不会在 ScriptB 访问数据时写入数据而破坏数据存储)。
当然,ScriptA 和 ScriptB 都可以将文件名或其他数据位置硬编码到它们的源中。但是,这将违反DRY Principle。因此,您可能希望他们共享一个配置文件。 (当然,配置文件名也在这些来源中重复......或者至少是配置代码的公共位的import......但后者仍然确保安装/配置详细信息(位置和可能的格式,数据存储的)与源代码解耦。因此可以更改(在共享配置中)而不影响任一脚本的其余代码。
至于具体使用哪种类型的文件和序列化......这是一个不同的问题。
现在,尽管听起来很奇怪,但我建议使用SQLite3。使用 SQL“数据库”来简单地存储单个值似乎有点过头了。但是 SQLite3 包含在 Python 标准库中,只需要一个文件名即可配置。
您也可以使用pickle 或JSON 甚至YAML(这将需要第三方模块)...甚至只是使用struct 之类的文本或一些二进制表示。但是,其中任何一个都需要您解析结果并处理任何解析或格式错误。 JSON 将是这些替代方案中最简单的选择。此外,如果您希望 ScriptA 和 ScriptB(可能还有您为操作此特定数据而编写的任何其他脚本)对任何并发操作的机会都具有鲁棒性,则您必须自己进行文件锁定和处理。
SQLite3 的优势在于它为您处理解析和解码以及锁定和并发。您创建一次表(可能嵌入在 ScriptA 中作为一个很少使用的“--initdb”选项,用于需要重新创建数据存储的场合)。你的阅读代码可能看起来很简单:
#!/usr/bin/python
import sqlite3
db = sqlite3.connect('./foo.db')
cur = db.cursor()
results = cur.execute(SELECT value, MAX(date) FROM results').fetchone()[0]
...写一个新值看起来有点像:
#!/usr/bin/python
# (Same import, db= and cur= from above)
with db:
cur.execute('INSERT INTO results (value) VALUES (?)', (myvalue,))
所有这一切都假设您曾在某个时候使用以下内容初始化数据存储(在此示例中为 foo.db):
#!/usr/bin/python
# (Same import, db= and cur= from above)
with db:
cur.execute('CREATE TABLE IF NOT EXISTS results (value INTEGER NOT NULL, date TIMESTAMP DEFAULT current_timestamp)')
(实际上,如果您希望脚本从清除旧数据中静默恢复,您可以每次都执行该命令)。
这似乎比基于 JSON 文件的方法更多的代码。然而,SQLite3 提供了ACID(transactional) 语义以及抽象出序列化和反序列化。
另外请注意,我在掩饰一些细节。我上面的示例实际上是创建一个完整的结果表,其中包含将它们写入数据存储区的时间戳。这些会随着时间的推移而累积,如果您使用这种方法,您会定期使用以下命令清理“结果”表:
#!/usr/bin/python
# (Same import, db= and cur= from above)
with db:
cur.execute('DELETE FROM results where date < ?', cur.execute('SELECT MAX(date) from results').fetchone())
或者,如果您真的不想访问从 INSERT 变为 UPDATE 的先前结果,如下所示:
#!/usr/bin/python
# (Same import, db= and cur= from above)
with db:
cur.execute(cur.execute('UPDATE results SET value=(?)', (mynewvalue,))
(还要注意(mynewvalue,) 是一个单元素元组。DBAPI 要求将我们的参数包装在元组中,当您第一次使用这样的单参数开始使用它时很容易忘记)。
显然,如果您采用这种仅更新的方法,您可以从“结果”表中删除“日期”列,并从查询中删除所有对 MAX(data) 的引用。
在我的早期示例中,我选择使用稍微复杂一点的架构,因为它们可以让您的脚本更加健壮,而且几乎没有额外的复杂性。然后,您可以进行其他错误检查,例如检测 ScriptB 发现 ScriptA 未按预期运行的缺失值。