Повторное чтение файла json на python. Данные файла используются только после первого открытия

Подскажите в чем может быть дело? При запуске скрипта считывается файл json

with open('C:\ping_data.json','r') as file:
    data = json.load(file)

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

if data[address.address] != status:

Почему-то в data остаются старые данные, а должны быть свежие из файла.

Кусок кода из бесконечного цикла:

    while True:

        for host in hosts_list:
            ping_host(host)

        with open('C:\ping_data.json','w') as file:
                json.dump(ping_data, file, indent=2)

        time.sleep(interval)

        with open('C:\ping_data.json','r') as file:
            data = json.load(file)

Полный код скрипта:

import telebot
from pythonping import ping
import time
import yaml
from libs.host import address
import json

ping_data = dict()
with open('C:\ping_data.json','r') as file:
    data = json.load(file)

def init():

    global bot, userid, interval

    interval = 30

    with open('C:\config.yaml', encoding="utf-8") as f:
        try:
            docs = yaml.load_all(f, Loader=yaml.FullLoader)

            for doc in docs:
                for k, v in doc.items():
                    if k == "botkey":
                        bot = telebot.TeleBot(v)
                    elif k == "userid":
                        userid = v
                    elif k == "hosts":
                        set_hosts(v)
                    elif k == "interval":
                        interval = int(v)

        except yaml.YAMLError as exc:
            print(exc)

def set_hosts(hosts):

    global hosts_list
    hosts_list = []

    for item in hosts:
        ac = item.split(":")
        hosts_list.append(address(ac[0], ac[1]))

def send_message(message):

    bot.send_message(userid, message)

def ping_host(address):

    status = ping_url(address.address)
    if data[address.address] != status:
        if status is None:
            send_message("! " + address.comment)
        else:
            if status:
                send_message("+ " + address.comment)
            else:
                send_message("- " + address.comment)
    ping_data[address.address] = status

def ping_url(url):

    try:
        response_list = ping(url, timeout=5, verbose = True)
    except:
        return None

    return sum(1 for x in response_list if x.success) > 0

def main():

    init()

    while True:

        for host in hosts_list:
            ping_host(host)

        with open('C:\ping_data.json','w') as file:
                json.dump(ping_data, file, indent=2)

        time.sleep(interval)

        with open('C:\ping_data.json','r') as file:
            data = json.load(file)

if __name__ == '__main__':
    main()

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

Автор решения: mrEvgenX

Обратим внимание на этот фрагмент кода:

def main():
    ...
    ...
        with open('C:\ping_data.json','r') as file:
            data = json.load(file)  # Создается локальная переменная data

Функция main обновляет только свою локальную переменную, а ping_host, хоть и вызываемый в main - использует глобальную.

Чтобы дать понять, что data должна браться из глобального контекста, надо в main первой строчкой написать:

def main():
    global data
    ...

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

Дополнительные материалы:

→ Ссылка