Повторное чтение файла 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 шт):
Обратим внимание на этот фрагмент кода:
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
...
Но такой подход может порождать трудноуловимые ошибки, связанные с побочными эффектами... Ну, как эта в приведенном вопросе. Правильнее будет не мутировать глобальное состояние, а передавать текущее состояние в аргументе и возвращать новое состояние.
Дополнительные материалы:
- https://ru.stackoverflow.com/questions/767668/Использование-global-в-python "Считайте каждое появление global в коде ошибкой, если нет особых причин для использования этой конструкции"
- https://python-scripts.com/scope "Комьюнити Python объявило такую практику очень нежелательной, так как из-за этого исправление кода становится намного сложнее."