我正在编写一个将变量作为字典导出到外部文件的函数。
从另一个脚本调用该函数时出现问题。我认为它与globals()
参数有关。
import sys
import os
mydict = {} #'initialising" the an empty dictionary to be used locally in the function below
def writeToValues(name):
fileName = os.path.splitext(os.path.basename(sys.argv[0]))[0]
valuePrint=open("values.py","a")
def namestr(obj,namespace):
return[name for name in namespace if namespace[name] is obj]
b = namestr(name, globals())
c = "".join(str(x) for x in b)
mydict[(c)] = name
valuePrint.write(fileName)
valuePrint.write("=")
valuePrint.write(str(mydict))
valuePrint.write("\n")
valuePrint.close()
return mydict
a = 2
b = 3
writeToValues(a)
writeToValues(b)
我得到以下结果:
Main Junkfile={'a': 2, 'b': 3}
注意单词Main Junkfile
是我运行的脚本的名称,因为这是函数首先执行的操作,以获取文件的名称并使用它来命名字典。
现在帮助我,因为如果我从另一个脚本导入函数,我就无法生成相同的内容。 另一个问题是,运行脚本两次会逐步生成值。
Main Junkfile={'a': 2}
Main Junkfile={'b': 3, 'a': 2}
我无法将文件打开模式从append更改为write,因为我也希望存储来自其他脚本的值。
答案 0 :(得分:1)
这并不完美,但可能会有所帮助:
import sys
import os
mydict = {}
def namestr(obj,namespace):
return[name for name in namespace if namespace[name] is obj]
def writeto(name):
fout = 'values.py'
filename = os.path.splitext(os.path.basename(sys.argv[0]))[0]
with open (fout, 'a') as f:
b = namestr(name, globals())
c = "".join(str(x) for x in b)
mydict[(c)] = name
data = filename + '=' + str(mydict) + '\n'
f.write(data)
return mydict
a = 2
b = 3
if __name__ == '__main__':
writeto(a)
writeto(b)
答案 1 :(得分:0)
首先,要获取当前正在执行的脚本名称,或者更确切地说是调用函数的模块,您必须从堆栈跟踪中获取它。同样适用于globals()
- 它将在writeToValues()
函数的相同上下文中执行,因此它不会从“来电者”中获取globals()
。要解决此问题,您可以使用inspect
模块:
import inspect
import os
def writeToValues(name):
caller = inspect.getmodule(inspect.stack()[1][0])
caller_globals = caller.__dict__ # use this instead of globals()
fileName = os.path.splitext(os.path.basename(caller.__file__))[0]
# etc.
这将确保您获得导入脚本并在其中调用writeToValues()
的模块的名称。
请记住,如果您打算编写可用的Python文件,这是一个非常糟糕的主意 - 如果您的脚本名称有空格(如您的示例中),它将使用空格写入变量名称,这将进一步导致语法错误如果您尝试将生成的文件加载到Python解释器中。
其次,为什么以蓬松的所有东西的名义,你试图进行反向查找以找到变量名称?你知道:
a = 2
b = 2
ab = 5
writeToValues(b)
将写{"ab": 2}
,而不是{"b": 2}
使其在意图中不正确(保存错误的var)以及状态表示(保存错误的值),对吧?您应该传递要存储/更新的变量名称,以确保您获得正确的属性。
更新部分更有问题 - 您需要更新文件,而不仅仅是附加到文件。这意味着您需要找到当前脚本的行,将其删除,然后在其位置写一个具有相同名称的新dict。如果你不希望你的文件增长到很大的比例(即你在部分工作记忆中感到舒服),你可以这样做:
import os
import inspect
def writeToValues(name):
caller = inspect.getmodule(inspect.stack()[1][0])
caller_globals = caller.__dict__ # use this instead of globals()
caller_name = os.path.splitext(os.path.basename(caller.__file__))[0]
# keep 'mydict' list in the caller space so multiple callers can use this
target_dict = caller_globals['mydict'] = caller_globals.get('mydict', {})
if name not in caller_globals: # the updated value no longer exists, remove it
target_dict.pop(name, None)
else:
target_dict[name] = caller_globals[name]
# update the 'values.py':
# optionaly check if you should update - if values didn't change no need for slow I/O
with open("values.py", "a+") as f:
last_pos = 0 # keep the last non-update position
while True:
line = f.readline() # we need to use readline() for tell() accuracy
if not line or line.startswith(caller_name): # break at the matching line or EOF
break
last_pos = f.tell() # new non-update position
append_data = f.readlines() # store in memory the rest of the file content, if any
f.seek(last_pos) # rewind to the last non-update position
f.truncate() # truncate the rest of the file
f.write("".join((caller_name, " = ", str(target_dict), "\n"))) # write updated dict
if append_data: # write back the rest of the file, if truncated
f.writelines(append_data)
return target_dict
否则使用临时文件在读取时写入所有内容,但与当前脚本匹配的行除外,为当前脚本添加新值,删除原始文件并将临时文件重命名为values.py
。 / p>
现在,如果您将上述内容存储在value_writter.py
中,并在脚本my_script.py
中将其用作:
import value_writter
a = 2
b = 3
value_writter.write_to_values("a")
value_writter.write_to_values("b")
a = 5
value_writter.write_to_values("a")
# values.py contains: my_script = {"a": 5, "b": 3}
同样适用于您导入它的任何脚本。现在,让多个脚本在没有锁定机制的情况下编辑同一个文件是一个等待发生的事故,但那是另一个故事。
此外,如果您的值很复杂,系统将会中断(或者您的dict的打印输出将无法正常显示)。帮自己一个忙,并使用一些正确的序列化,即使可怕的pickle
比这更好。