Как лучше всего позволить двум классам общаться друг с другом в Python? - PullRequest
0 голосов
/ 16 апреля 2020

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

import random

class GuessGame:
    def __init__(self, controller, n = 100):
        self.controller = controller
        self.n = n

    def run(self):
        number = random.randrange(self.n)
        self.interact(number)

    def interact(self, number):
        self.controller.inform_n(self.n)
        while True:
            guess = self.controller.get_guess()
            if guess == number:
                self.controller.inform_result(0)
                return
            elif guess < number:
                self.controller.inform_result(-1)
            else:
                self.controller.inform_result(1)

class GuessAgent:
    def __init__(self, environment, n = 100):
        self.environment = environment
        self.n = n

    def run(self):
        x0 = 0
        x1 = self.n
        while True:
            x = (x0 + x1) // 2
            result = self.environment.guess(x)
            if result == 0:
                return
            elif result == -1:
                x0 = x + 1  # Inclusive lower bound
            else:
                x1 = x      # Exclusive upper bound

if __name__ == '__main__':
    class ManualController:
        def inform_n(self, n):
            print(f'n = {n}')

        def inform_result(self, result):
            print({0: 'Correct', -1: 'Too low', 1: 'Too high'}[result])

        def get_guess(self):
            return int(input())

    class ManualEnvironment:
        def guess(self, n):
            print(f'Guess: {n}')
            print('0 = Correct, -1 = Too low, 1 = Too high')
            return int(input())

    GuessGame(ManualController()).run()
    GuessAgent(ManualEnvironment()).run()

Как видно, они оба отлично работают со своими собственными интерфейсами. Проблема в том, что они оба хотят быть процедурой верхнего уровня, которая вызывает другую сторону, поэтому нет очевидного способа соединить их. В случае с реальным миром оба класса довольно сложны (и могут быть написаны кем-то другим), поэтому «просто переписать один из них» - нежелательный ответ.

Решения, которые я могу придумать являются:

  1. Сделать их отдельными подпроцессами. Это работает, но мне кажется слишком жестким подходом ко мне. Я только пытаюсь запустить симуляцию, и я боюсь, что общение на уровне ОС потребует слишком много накладных расходов.
  2. Сделайте одну из них функцией генератора. Помимо того, что я не очень интуитивно понятен, самая большая проблема, с которой я сталкиваюсь при таком подходе, заключается в том, что некоторые операторы коммуникации довольно глубоко скрыты в дереве вызовов (я сделал GuessGame.interact отдельной функцией, чтобы проиллюстрировать это), и мне нужно изменить все функции в цепочке вызовов для функций генератора, чтобы сделать эту работу. Было бы приемлемо, если бы мне нужно было только изменить некоторый код в точке операторов связи и, возможно, в точках входа, но все в цепочке вызовов слишком много.

Есть ли более элегантный шаблон для решения такого рода проблем?

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