2017-05-24 16 views
0

変数を辞書として外部ファイルにエクスポートする関数を書いています。 問題は、別のスクリプトからその関数を呼び出すときに発生します。私はそれがglobals()パラメータと関係があると思います。単語Main Junkfileは私がそのよう走ったスクリプトの名前です関数を使用して複数の変数をファイルに書き込む

Main Junkfile={'a': 2, 'b': 3} 

ノート機能は、最初のファイルと使用の名前を取得するには、何をされています

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) 

私は、次のような結果を得ます辞書に名前を付けること。

他のスクリプトから関数をインポートすると、同じものを生成できないので、今私を助けてください。 別の問題は、スクリプトを2回実行すると、ステップで値が生成されることです。

Main Junkfile={'a': 2} 
Main Junkfile={'b': 3, 'a': 2} 

他のスクリプトの値も保存したいので、ファイルオープンモードをappendからwriteに変更できません。

+0

もしもその別のスクリプトがPythonでもあれば、あなたは典型的なものがありません:もし__name__ == "__main__"ならば、 – Drako

答えて

0

まず、現在実行中のスクリプト名を取得するために、またはあなたの関数を呼び出したモジュールむしろ、あなたがそれをピックアップする必要がありますスタックトレースから取得します。 globals()の場合も同じです。writeToValues()と同じコンテキストで実行されるので、 'caller'から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インタプリタにロードしようとすると、エラーが発生します。

第2に、すべてのものの名前でふわふわして、変数名を見つけるために逆引き参照をしようとしているのですか?あなたはことを知っている:

a = 2 
b = 2 
ab = 5 

writeToValues(b) 

{"ab": 2}を書きますし、それが正しい、などの状態表現(間違った値を保存します)目的で不正な(間違ったVARを節約できます)、両方作っていない{"b": 2}?変数を渡して、適切なプロパティを確実に取得できるように保存/更新してください。

アップデートの問題はより問題になります。単にファイルを追加するだけでなく、ファイルを更新する必要があります。つまり、現在のスクリプトの行を見つけて削除し、同じ名前の新しい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に変更します。

だから今、あなたは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がこれよりも優れています。

+0

zwer、上記はすべて私の質問に答えます。そしてあなたが正しいです。値ファイルは追加され、置き換えられないため指数関数的に増加します。また逆引き参照は、値が同じであるときに間違っています。私はpickleまたはsqlite3データベースを避けようとしていました。別のスクリプトで使用する変数をエクスポートするより良い方法はありますか?主に数学的な文脈の中で、私は異なるファイルで複数の計算に変数値を使用し、それらを更新します。私はプログラミングの初心者です –

+0

あなたのデータをシリアライズしてスクリプト間で共有する方法は、データに依存します - 純粋なPythonでは、ファイルに '' "、"。join(your_numbers) 'ファイルを読み込んでそれを検索し、file_content.split( "、")]のnumに対してyour_numbers = [float(num)]を実行すれば十分です。より複雑な構造の場合、JSONを使用することができます - それは十分速く、ほとんどの '魔法'自体を行います。あなたのプロジェクトに 'numpy'依存関係を追加したいのであれば、それはいくつかの邪悪な速いファイルの格納と取り出しの方法を持っていますので、それを確かめてください。 – zwer

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) 
+0

のインポートファイル名の作成時に期待どおりに動作しない可能性があります。 – Drako

関連する問題