我有两个python脚本,scriptA和scriptB,它们运行在Unix系统上。 scriptA需要20秒才能运行并生成一个数字X. scriptB在运行时需要X,大约需要500ms。我需要每天运行scriptB,但每个月只运行一次scriptA。所以我不想从scriptB运行scriptA。每次运行scriptA时,我也不想手动编辑scriptB。我想过通过scriptA更新文件,但我不确定理想情况下这样的文件放在哪里,以便scriptB以后可以读取它;独立于这两个脚本的位置。在Unix系统中存储此值X的最佳方法是什么,以便以后可以通过scriptB使用?
答案 0 :(得分:3)
Linux / Unix中的许多程序都在/etc/
中保留配置,并在/var/
中使用子文件夹来保存其他文件。
但是你可能需要root权限。
如果您在主文件夹中运行脚本,则创建文件~/.scripB.rc
或文件夹~/.scriptB/
或~/.config/scriptB/
答案 1 :(得分:3)
听起来你想序列化ScriptA的结果,将其保存在某个文件或数据库中,然后让ScriptB读取这些结果(可能还修改文件或更新数据库条目以表明这些结果现在已经有了已经处理完毕。)
为了完成这项工作,您需要ScriptA和ScriptB就数据的位置和格式达成一致......您可能希望实现某种锁定以确保ScriptB不会以损坏的输入结束如果它恰好在ScriptA正在编写或更新数据的同时运行(相反,当ScriptB访问它时,ScriptA不会通过写入来破坏数据存储)。
当然,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(事务性)语义以及抽象化序列化和反序列化。
另请注意,我对一些细节进行了修饰。我上面的示例实际上是创建一个完整的结果表,其中包含写入数据存储区的时间戳。随着时间的推移,这些会累积起来,如果你使用这种方法,你会定期想要清理你的结果"使用如下命令的表:
#!/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要求我们的参数包含在元组中,当您第一次开始使用单个参数时很容易忘记这些元素。
显然,如果你采用这种UPDATE方法,你可以放弃“约会”日期&#39;来自&#39;结果&#39;的列表和查询中对MAX(data)
的所有引用。
我选择在我的早期示例中使用稍微复杂的模式,因为它们允许您的脚本更加健壮,而且几乎没有额外的复杂性。然后,您可以执行其他错误检查,检测缺失值,其中ScriptB发现ScriptA未按预期运行,例如)。
答案 2 :(得分:1)
假设您没有同时运行这两个脚本,只要加载并保存文件时指向同一系统路径,就可以(pickle和)在对象之间保存go。例如:
import pickle # or import cPickle as pickle
# Create a python object like a dictionary, list, etc.
favorite_color = { "lion": "yellow", "kitty": "red" }
# Write to file ScriptA
f_myfile = open('C:\\My Documents\\My Favorite Folder\\myfile.pickle', 'wb')
pickle.dump(favorite_color, f_myfile)
f_myfile.close()
# Read from file ScriptB
f_myfile = open('C:\\My Documents\\My Favorite Folder\\myfile.pickle', 'rb')
favorite_color = pickle.load(f_myfile) # variables come out in the order you put them in
f_myfile.close()
答案 3 :(得分:1)
修改/运行crontab -e
:
# this will run every month on the 25th at 2am
0 2 25 * * python /path/to/scriptA.py > /dev/null
# this will run every day at 2:10 am
10 2 * * * python /path/to/scriptB.py > /dev/null
为两个脚本创建外部文件:
在scriptA中:
>>> with open('/path/to/test_doc','w+') as f:
... f.write('1')
...
在scriptB中:
>>> with open('/path/to/test_doc','r') as f:
... v = f.read()
...
>>> v
'1'
答案 4 :(得分:1)
您可以查看PyPubSub 它是一个python包,它提供了一个发布 - 订阅Python API,可以促进基于事件的编程。
它将为您提供一个独立于操作系统的解决方案,只需要在A和B中只需要很少的代码行。
此外,您不需要处理凌乱的文件!