Сохранение настроек переменной

Мне нужно сделать так ,чтобы при нажатии на кнопку, путь приложения которое вызывает эта кнопка сохранялся в отдельный файл, а при перезагрузке скрипта всё становилось также, а не сбрасывалось.Прошу помочь с этим, ведь не имею представления как сохранять переменную и как ставить условие.

Мой код:

import tkinter.filedialog as tfd
import tkinter as tk
import os


window = tk.Tk()
window.title("Мой Открыватель")
window.geometry("600x400")
window.resizable(False, False)

file_name = ""



def open():
    global file_name
    if file_name == "":
        file_name = tfd.askopenfilename()
        os.startfile(file_name)
    else:
        os.startfile(file_name)
    if btn1["text"] == "":
        btn1["text"] = file_name



btn1 =  tk.Button(window, text="", command=open)
btn1.place(x = 20, y = 25)


window.mainloop()

Ответы (1 шт):

Автор решения: 0dminnimda

Как сохранить данные из питона?

Самый простое способ - использовать встроенный модуль - pickle Он может "замариновать" объект в питоне с помощью pickle.dump(obj, file) И загрузить "замаринованный" объект обратно с помощью obj = pickle.load(file)

Для этого нам надо открывать файлы и помнить путь сохранения, звучит не очень просто, тогда давайте создадим класс, который будет отвечать именно за это:

@dataclass
class Saver:
    filename: str

    def save(self, data):
        with open(self.filename, "wb") as file:
            pickle.dump(data, file)

    def load(self):
        with open(self.filename, "rb") as file:
            return pickle.load(file)

    def save_exists(self):
        return os.path.exists(self.filename)

Метод save будет сохранять объект в путь, перезаписывая что-либо, если что-то было.
Метод load загрузит сохранение из пути, если сохранение не существует, то поднимет ошибку.
Метод save_exists проверит, есть ли сохранение.


@dataclass здесь просто заменяет нам нужду в __init__ иначе можно было бы написать

def __init__(self, filename):
    self.filename = filename

Что мы будем сохранять?

Данные? какие? Давайте определим класс со всеми данными, которые мы будем сохранять, пока что это только путь к файлу:

@dataclass
class Data:
    filename: str = "<нет сохранения>"

По умолчанию путь это строка "<нет сохранения>"

Загрузка сохранения

давайте определим функцию, которая попробует загрузить сохранение, и если его нет, то просто вернёт новый объект с данными по умолчанию:

def try_to_load(saver):
    if saver.save_exists():
        print("загружаем сохранение")
        return saver.load()

    print("нет сохранения")
    return Data()

Главная часть программы

здесь находится вся настройка (окно tk, путь сохранения, положения кнопок)

window = tk.Tk()
window.title("Мой Открыватель")
window.geometry("600x400")
window.resizable(False, False)

saver = Saver("save.pickle")
data = try_to_load(saver)

open_button = tk.Button(
    window, text=data.filename, command=on_open)
open_button.place(x=20, y=25)

window.mainloop()

И заметим, что в кнопке мы сразу же используем данные из try_to_load (text=data.filename)


Но подождите, тут есть какая-то функцию on_open, мы её не определяли!
Всему своё время, сейчас определим:

При нажатии кнопки

мы хотим получить путь, если мы его не знаем и сохранить его, иначе можно ничего не делать.

def on_open():
    if data.filename != Data.filename:
        print("уже есть сохранение")
        return

    data.filename = tfd.askopenfilename()
    saver.save(data)
    print("сохранили")

    os.startfile(data.filename)
    open_button["text"] = data.filename

Здесь data.filename != Data.filename проверяет значение на факт того, было ли оно изменено, т.к. Data.filename == "<нет сохранения>" (как мы и объявляли в нашем классе с данными), и если data.filename было изменено на реальный путь, то оно не будет иметь то значение по умолчанию.

В остальном функция какая же, запрашивает путь, изменяет данные на путь, сохраняет данные и тд...

Одно целое

В итоге у нас получился такой код:

import os
import pickle
import tkinter as tk
import tkinter.filedialog as tfd
from dataclasses import dataclass


@dataclass
class Saver:
    filename: str

    def save(self, data):
        with open(self.filename, "wb") as file:
            pickle.dump(data, file)

    def load(self):
        with open(self.filename, "rb") as file:
            return pickle.load(file)

    def save_exists(self):
        return os.path.exists(self.filename)


@dataclass
class Data:
    filename: str = "<нет сохранения>"


def try_to_load(saver):
    if saver.save_exists():
        print("загружаем сохранение")
        return saver.load()

    print("нет сохранения")
    return Data()


def on_open():
    if data.filename != Data.filename:
        print("уже есть сохранение")
        return

    data.filename = tfd.askopenfilename()
    saver.save(data)
    print("сохранили")

    os.startfile(data.filename)
    open_button["text"] = data.filename


window = tk.Tk()
window.title("Мой Открыватель")
window.geometry("600x400")
window.resizable(False, False)

saver = Saver("save.pickle")
data = try_to_load(saver)

open_button = tk.Button(
    window, text=data.filename, command=on_open)
open_button.place(x=20, y=25)

window.mainloop()

→ Ссылка