Добрый день, уважаемые знатоки.
Работаю над скриптом, использующим сетевое реле для перезагрузки видеокамер, и столкнулся с вопросом о реализации счетчика. Я проверяю доступность камер с помощью цикличного пинга, и мне нужно создать элегантный счетчик, который, например, будет запускать функцию перезагрузки после 5 неудачных попыток, а также отслеживать общее количество перезагрузок.
Я понимаю, что это можно сделать с использованием глобальных переменных, но во время поиска информации наткнулся на мнение, что глобальные переменные — это плохо, без пояснений причин. С учетом моего опыта, мне бы хотелось понять, как можно реализовать эту задачу корректно и согласно лучшим практикам.
Вот пример метода, который я использую:
<pre><code class="python">IP12 = '192.168.0.100'
IP13 = '192.168.0.101'
RODOS12 = '192.168.1.100'
RODOS13 = '192.168.1.101'
def cameras_checker(self):
while True:
r_dict = {'Купол 12': IP12, 'Купол 13': IP13}
for key, val in r_dict.items():
cmd = f'ping {val} -n 1 -w 100'
response = subprocess.call(cmd, stdout=subprocess.DEVNULL)
if not response:
print(f'Camera {key} - OK')
счетчик неудач 12 или 13 купола = 0 # Обнуляем при успешном пинге
else:
if key == 'Купол 12':
счетчик неудач 12 купола += 1 # Увеличиваем счетчик для 12 купола
print(f'Camera {key} - Died')
if счетчик неудач 12 купола == 5:
self.cameras_reboot(RODOS12)
else:
счетчик неудач 13 купола += 1 # Увеличиваем счетчик для 13 купола
print(f'Camera {key} - Died')
</code></pre>
Как можно организовать эту логику без использования глобальных переменных?
Для решения вашей задачи без использования глобальных переменных вы можете использовать класс для инкапсуляции состояния счетчиков и логики работы с камерами. Таким образом, состояние (например, количество неудачных попыток и количество перезагрузок) будет связано с экземпляром класса.
Вот пример, как это можно реализовать:
```python
import subprocess
import time
class CameraManager:
def __init__(self, camera_ips, reboot_ips):
self.camera_ips = camera_ips # Словарь с именами камер и их IP
self.reboot_ips = reboot_ips # Словарь с именами камер и IP для перезагрузки
self.failure_counters = {key: 0 for key in camera_ips.keys()} # Счетчики неудачных попыток
self.reboot_count = 0 # Общее количество перезагрузок
def ping_camera(self, ip):
cmd = f'ping {ip} -n 1 -w 100'
return subprocess.call(cmd, stdout=subprocess.DEVNULL) == 0
def cameras_checker(self):
while True:
for key, val in self.camera_ips.items():
if self.ping_camera(val):
print(f'Camera {key} - OK')
self.failure_counters[key] = 0 # Обнуляем счетчик при успешном пинге
else:
print(f'Camera {key} - Died')
self.failure_counters[key] += 1 # Увеличиваем счетчик для камеры
if self.failure_counters[key] == 5:
self.reboot_camera(key)
time.sleep(1) # Задержка между проверками
def reboot_camera(self, camera_name):
if camera_name in self.reboot_ips:
print(f'Rebooting {camera_name}...')
# Здесь можно добавить код для отправки команды на перезагрузку
self.reboot_count += 1 # Увеличиваем общий счетчик перезагрузок
print(f'Total reboots: {self.reboot_count}')
self.failure_counters[camera_name] = 0 # Обнуляем счетчик неудач после перезагрузки
if __name__ == "__main__":
camera_ips = {
'Купол 12': '192.168.0.100',
'Купол 13': '192.168.0.101',
}
reboot_ips = {
'Купол 12': '192.168.1.100',
'Купол 13': '192.168.1.101',
}
manager = CameraManager(camera_ips, reboot_ips)
manager.cameras_checker()
```
### Объяснение реализации:
1. **Класс `CameraManager`**:
- Инициализируется с двумя словарями: один для IP камер и другой для IP реле перезагрузки.
- Содержит `failure_counters` для отслеживания неудачных попыток пинга каждой камеры.
- Также содержит `reboot_count` для подсчета общего количества перезагрузок.
2. **Метод `ping_camera`**:
- Определяет, доступна ли камера, возвращая `True` или `False`.
3. **Метод `cameras_checker`**:
- Работает в бесконечном цикле. Пингует каждую камеру и обновляет соответствующий счетчик.
- Если после 5 неудачных попыток, инициируется перезагрузка с помощью метода `reboot_camera`.
4. **Метод `reboot_camera`**:
- Здесь можно добавить логику для фактической перезагрузки камеры и обновления счетчиков.
### Преимущества данного подхода:
- Избегая глобальных переменных, вы улучшаете читаемость и поддержку кода.
- Инкапсуляция состояния в классе позволяет лучше управлять состоянием приложения.
- Код легче тестировать и расширять в будущем.
Как-то так <br/> <pre><code class="python">def cameras_checker(self):
cameras = [
{'name': 'Купол 12', 'ip': IP12, 'rebootIp': RODOS12, 'fails': 0},
{'name': 'Купол 13', 'ip': IP13, 'rebootIp': RODOS13, 'fails': 0},
]
while True:
for camera in cameras:
cmd = f"ping {camera['ip']} -n 1 -w 100"
response = subprocesscall(cmd, stdout=subprocess.DEVNUL)
if not response:
print(f'Camera {camera['name']} ok')
camera['fails'] = 0
else:
camera['fails'] += 1
print(f"Camera {camera['name']} died")
if camera['fails'] = 5:
self.cameras_reboot(camera['rebootIp'])
sleep(5)</code></pre>
По <b>феншую</b> и <b>правильно</b> по хорошему бы реализовать класс, в котором будешь хранить состояние счётчиков <br/> <br/> <pre><code class="python">import subprocess
from time import sleep
class CameraMonitor:
def __init__(self):
self.IP12 = '192.168.0.100'
self.IP13 = '192.168.0.101'
self.RODOS12 = '192.168.1.100'
self.RODOS13 = '192.168.1.101'
self.fail_count = {'Купол 12': 0, 'Купол 13': 0}
self.reboot_count = {'Купол 12': 0, 'Купол 13': 0}
def ping_camera(self, ip):
cmd = f'ping {ip} -n 1 -w 100'
response = subprocess.call(cmd, stdout=subprocess.DEVNULL)
return response == 0
def cameras_checker(self):
r_dict = {'Купол 12': self.IP12, 'Купол 13': self.IP13}
while True:
for camera, ip in r_dict.items():
if self.ping_camera(ip):
print(f'Camera {camera} - OK')
self.fail_count[camera] = 0
else:
self.fail_count[camera] += 1
print(f'Camera {camera} - Died')
if self.fail_count[camera] >= 5:
self.cameras_reboot(camera)
sleep(5)
def cameras_reboot(self, camera):
if camera == 'Купол 12':
ip = self.RODOS12
else:
ip = self.RODOS13
self.reboot_count[camera] += 1
print(f'Rebooting {camera} at IP {ip}')
def info(self):
for camera, count in self.reboot_count.items():
print(f'Перезагрузок {camera}: {count}')
if __name__ == "__main__":
monitor = CameraMonitor()
monitor.cameras_checker()</code></pre>