0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

永続的に変数を保存する(Python)

Last updated at Posted at 2021-09-27

永続的な変数作る

変数を永続的に保存したいことはよくあることだと思います
例えば、ウインドウプログラムの座標やサイズ、設定項目などです

Serializeとかで検索すれば、色々な言語でこのようなことをするものが出てくるのですが、Pythonではpickleを使うのが多分普通なんじゃ無いかと思います。楽です。

それでももっと楽したい

ので、つくってみたのがこれです。

persistentvals.py
from typing import Any
import os.path, pickle

class _Old:
    def __init__(self, filename: str) -> None:
        if os.path.exists(filename):
            with open(filename, "rb") as f:
                tmp = pickle.load(f)
            self.__dict__.update(tmp)

class PersistentVals:
    def __init__(self, filename: str) -> None:
        object.__setattr__(self, "_PersistentVals__filename", filename)
        object.__setattr__(self, "_old", _Old(filename))

    def print(self) -> None:
        for i,v in self.__dict__.items():
            if i != '_PersistentVals__filename':
                print(i, '=', v)
    
    def __setattr__(self, name: str, value: Any) -> None:
        if name in self.__dict__.keys():
            object.__setattr__(self, name, value)
        else:
            if name in self._old.__dict__.keys():
                if type(value) is type(self._old.__dict__[name]):
                    object.__setattr__(self, name, self._old.__dict__[name])
                else:
                    object.__setattr__(self, name, value)
            else:
                object.__setattr__(self, name, value)

    def __del__(self) -> None:
        if hasattr(self, '_old'):
            del self._old
        with open(self.__filename, "wb") as f:
            del self.__filename
            pickle.dump(self.__dict__,f)

class NotPersistentVals:
    def __init__(self, filename: str) -> None:
        pass

    def print(self):
        for i,v in self.__dict__.items():
            print(i,'=',v)

どういうものなの?

変数を勝手に保存するクラスです。クラス自体はほぼ空っぽなので
p = persistentvals.PersistentVals('savedata')
のようにインスタンスを作ったら
p.hoge = 'こんにちは'
のように普通にプロパティを追加していって下さい。
このとき、過去にp.hogeに何らかの値が代入されていて、savedataに保存されている場合、
p.hogeには"こんにちは"は代入されずに、savedataに保存されている物が代入されます。

どういう作り?

インスタンスを作成したときに、保存された変数データを読み込み、変数が初めて代入されたときに保存されたデータと比較して、同じ型、同じ名前のものがあれば保存されたデータを代わりに代入します。

どう使うの?

普通に、保存したい変数はこのクラスのプロパティに入れる形で初期化してください。
普通の形で初期化していても、保存した値になるので、便利かもしれません。

example.py
import persistentvals

p = persistentvals.PersistentVals("./test.dat")
p.foo = "Hello World" #二度目以降の実行ではこれは代入されない
print(p.foo)

# p.foo = 10
# print(p.foo) # 10
# 例外として、最初の代入でも保存されている物と型が違う場合は代入される

p.foo = "こんにちは、世界" # 最後に代入された物が保存される

p.lists = [1,2,3,4,5,6,7,8,9,10]
print(p.lists)
p.lists = [10,9,8,7,6,5,4,3,2,1,0]
print(p.lists)
# リストの場合

p.print() #定義されている変数の一覧が出ます

注意事項

このクラスは(多分)便利ですが、変数に値を代入したら変数にはその値が入ると言うプログラムの常識を覆すクラスです。デバッグに支障が出ること間違いありません、使用には十分注意してください。

persistentvals.NotPersistentValsと言う本当に何もしないクラスが付属しています。使い方は同じですが、何もしないので少なくともデバッグ時にはこれを使用することを推奨します

このクラスはメモリ内に前回に保存した変数の内容を全て保存します。なので、あまり大きな配列などを入れるとメモリを無駄に使用するので、あまり大きな配列は入れない方が良いと思われます。

追記

あと、Singletonなクラスにした方が、便利かもしれないなあとか思った。

修正

_oldの削除に失敗するのを修正(2022/01/25)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?