Как можно вызвать метод дочернего класса из метода родительского класса в объектно-ориентированном программировании?

Добрый вечер! Я изучаю основы ООП и столкнулся с некоторыми трудностями. У меня есть родительский класс `App`, а также два дочерних класса: `Cameras` и `Orion`. Вот пример кода:

```python
class App():
    def __init__(self):
        self.host = socket.gethostname()
        self.camera_fail = {'Купол 12': 0, 'Купол 13': 0}
        self.camera_reboot = {'Купол 12': 0, 'Купол 13': 0}
        self.date = datetime.now().strftime("%d-%m-%Y_%H:%M")

    def starting(self):
        thr2 = threading.Thread(target=self.tray_main, daemon=True)  # Запускаем в субпотоке Трей
        thr2.start()
        while True:  # В цикле запускаем классы в зависимости от результата if
            if self.host == 'ARM-KTCO':
                Cameras()
            else:
                Orion()
            sleep(5)

    def tray_main(self):  # Метод работы меню Трея
        image = Image.open('tnt.ico')
        if self.host == 'ARM-KTCO':
            icon = Icon('Boo', image,
                         menu=Menu(MenuItem('Ребут купол 12', self.tray_click),
                                   (MenuItem('Ребут купол 13', self.tray_click)),
                                   (MenuItem('Инфо', self.cameras_status_message)),
                                   MenuItem('Выход', self.tray_click)))
            icon.run()

    def tray_click(self, icon: Icon, item: MenuItem):  # Метод реакции на выбор меню Трея
        if str(item) == 'Ребут купол 12':
            print('НАЖАТО Перезагрузить Купол 12')
---------------------------------------------------------
            Cameras.cameras_reboot(???) 
---------------------------------------------------------
        elif:.
        elif..

class Cameras(App):
    def __init__(self):
```

Не могли бы вы помочь мне понять, как лучше организовать вызов метода `cameras_reboot` для дочернего класса `Cameras`, в том числе, что должно быть передано в качестве аргумента?
  • 24 сентября 2024 г. 21:13
Ответы на вопрос 1
В вашем случае для того, чтобы вызвать метод дочернего класса `Cameras` из метода родительского класса `App`, необходимо создавать экземпляр дочернего класса, чтобы получить доступ к его методам. Однако в вашем коде есть несколько важных моментов, которые нужно учесть: вы вызываете `Cameras()` и `Orion()` внутри метода `starting`, но не сохраняете созданные экземпляры в переменные, поэтому вы не сможете позже вызывать их методы.

Вот как вы можете организовать ваш код:

1. Создайте экземпляры дочерних классов и сохраняйте их в переменных.
2. Используйте эти экземпляры для вызова методов.

Вот пример модифицированного кода:

```python
import socket
import threading
from datetime import datetime
from time import sleep
from PIL import Image
from some_tray_library import Icon, Menu, MenuItem  # Замените на вашу библиотеку

class App():
    def __init__(self):
        self.host = socket.gethostname()
        self.camera_fail = {'Купол 12': 0, 'Купол 13': 0}
        self.camera_reboot = {'Купол 12': 0, 'Купол 13': 0}
        self.date = datetime.now().strftime("%d-%m-%Y_%H:%M")
        self.cameras_instance = None
        self.orion_instance = None

    def starting(self):
        self.cameras_instance = Cameras()  # Создайте экземпляр Cameras
        self.orion_instance = Orion()      # Создайте экземпляр Orion
        
        thr2 = threading.Thread(target=self.tray_main, daemon=True)  # Запускаем в субпотоке Трей
        thr2.start()
        while True:  # В цикле запускаем классы в зависимости от результата if
            if self.host == 'ARM-KTCO':
                self.cameras_instance.start()  # Запустить методы экземпляра Cameras
            else:
                self.orion_instance.start()      # Запустить методы экземпляра Orion
            sleep(5)

    def tray_main(self):
        image = Image.open('tnt.ico')
        if self.host == 'ARM-KTCO':
            icon = Icon('Boo', image,
                         menu=Menu(
                             MenuItem('Ребут купол 12', self.tray_click),
                             MenuItem('Ребут купол 13', self.tray_click),
                             MenuItem('Инфо', self.cameras_status_message),
                             MenuItem('Выход', self.tray_click)
                         ))
            icon.run()

    def tray_click(self, icon: Icon, item: MenuItem):
        if str(item) == 'Ребут купол 12':
            print('НАЖАТО Перезагрузить Купол 12')
            self.cameras_instance.cameras_reboot('Купол 12')  # Здесь вызываем метод
        elif str(item) == 'Ребут купол 13':
            print('НАЖАТО Перезагрузить Купол 13')
            self.cameras_instance.cameras_reboot('Купол 13')  # Здесь вызываем метод
        elif str(item) == 'Выход':
            icon.stop()

class Cameras(App):
    def __init__(self):
        super().__init__()

    def start(self):
        print("Камеры запущены")

    def cameras_reboot(self, dome_name):
        print(f'Перезагрузка {dome_name}')

class Orion(App):
    def __init__(self):
        super().__init__()

    def start(self):
        print("Орион запущен")

# Пример использования
if __name__ == "__main__":
    app = App()
    app.starting()
```

### Объяснение изменений:

1. **Хранение экземпляров:** Я добавил два атрибута `self.cameras_instance` и `self.orion_instance`, чтобы хранить созданные экземпляры классов `Cameras` и `Orion`.

2. **Старт методов:** В методе `starting` создаются экземпляры этих классов, и они могут быть запущены с помощью метода `start`, если это нужно.

3. **Вызов методов:** При нажатии на соответствующие пункты меню в методе `tray_click`, выполняется вызов метода `cameras_reboot`, передавая аргумент, соответствующий куполу.

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