Pythonic развязка входного и результирующего объекта - PullRequest
0 голосов
/ 14 октября 2019

У меня есть различные входные потоки, которые предоставляют информацию, которую я хочу упаковать в объект, который я затем могу передать отдельным функциям:

class FruitBasket:
    def __init__(self, a, b, c, **kwargs):
        self.a = a
        self.b = b
        self.c = c

Однако каждый поток данных называет данные, которые я ищу, по-своему. Входные данные StreamA выглядят так:

{"apple" : 3, "banana" : 2, "citrus" : 0}

, а входные данные StreamB выглядят следующим образом:

{"fruit1" : 1, "fruit2" : 7, "fruit3" : 4, "dog" : 21}

В настоящее время мое решение для этого состоит в том, чтобы иметь отдельный класс, который отображает информацию между входными даннымии вывод объекта:

class StreamAMap(Enum):
    a = "apple"
    b = "banana"
    c = "citrus"

class StreamBMap(Enum):
    a = "fruit2"
    b = "fruit1"
    c = "fruit3"

Затем я передаю и этот класс "map", целевой объект и входные данные в функцию:

def translate(map_enum, target, data):
    translation = {}

    for item in map_enum:
        translation[item.name] = data[item.value]

    return(target(**translation))

data_a = {"apple" : 3, "banana" : 2, "citrus" : 0}
data_b = {"fruit1" : 1, "fruit2" : 7, "fruit3" : 4, "dog" : 21}

basket_1 = translate(StreamAMap, FruitBasket, data_a)
basket_2 = translate(StreamBMap, FruitBasket, data_b)

Это работает, но яИнтересно, есть ли более Pythonic способ достижения этого.

edit: Цель здесь состоит в том, чтобы сохранить FruitBasket полностью отделенным от любого потока, который может произвести данные, которые заканчиваются в нем, то естькаждый поток знает, какая информация должна поступить в FruitBasket, но независимо от того, какие потоки будут добавлены или удалены в будущем, мне не нужно ничего менять в классе FruitBasket, а лишь гарантирую, что каждый потоквозвращение действительного FruitBasket в основное приложение. Моя текущая реализация требует, чтобы для каждого нового потока, который я добавлял, был определен только класс "map", и мне интересно, есть ли "Pythonic" (встроенный) способ сделать это вместо того, чтобы использовать собственную функцию перевода для этого.

Чтобы прояснить, что я подразумеваю под "Pythonic", "Pythonic" способ определения среднего значения списка - это sum(list) / len(list) вместо того, чтобы перебирать список для увеличения переменной счетчика и добавления каждого элемента впеременная суммы.

Ответы [ 2 ]

3 голосов
/ 14 октября 2019

Забудьте о «Pythonic», забудьте о «ООП правильном пути» и подумайте о том, как сохранить здравомыслие. Очевидный способ сохранить ваше здравомыслие - «ООП правильно» и «Пифоник».

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

Очевидное решение состоит в том, чтобы в вашей системе был класс, который будет вести себя одинаково, с четко определенными атрибутами и методами, и иметь способ создания объекты этого класса, которые могут справиться с неоднородным вводом данных. И то же самое для вывода - если у вас есть требование выводить информацию в более чем одной форме, вы пишете методы для преобразования вашей (унифицированной, в приложении) информации в конкретную форму, требуемую для каждого выходного канала.

Говоря более конкретно: в вашем классе должны быть поля, которые вам нужны для основной деятельности вашего приложения в качестве атрибутов, и либо они должны иметь пойморфный метод инициализатора, различные вспомогательные методы для создания экземпляров из каждого типа ввода или фабричную функцию (или наборфабричных функций) для создания ваших экземпляров.

Но как только они будут созданы, все они должны просто иметь атрибуты a, b и c.

Второй шаблон изварианты, которые я дал выше, могли бы быть хорошим началом:

class FruitBasket:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
    @classmethod
    def from_named_stream(self, stream):
        return FruitBasket(a=stream["apple"], b=stream["banana", c=stream["citrus"]) 

    # go on and create one such classmethod for each form of input data

0 голосов
/ 19 октября 2019

Итак, я нашел способ сделать это очень просто и кратко:

class FruitBasket:
    def __init__(self, a, b, c, **kwargs):
        self.a = a
        self.b = b
        self.c = c

class FruitBasketIntermediateA:
    def __init__(self, apple, banana, citrus, **kwargs):
        self.a = apple
        self.b = banana
        self.c = citrus

class FruitBasketIntermediateB:
    def __init__(self, fruit1, fruit2, fruit3, **kwargs):
        self.a = fruit2
        self.b = fruit1
        self.c = fruit3

data_a = {"apple" : 3, "banana" : 2, "citrus" : 0}
data_b = {"fruit1" : 1, "fruit2" : 7, "fruit3" : 4, "dog" : 21}

my_fb_a = FruitBasket(**vars(FruitBasketIntermediateA(**data)))
my_fb_b = FruitBasket(**vars(FruitBasketIntermediateB(**data)))

Если бы я потреблял сотни тысяч сообщений в секунду, мне, вероятно, пришлось бы использовать что-то более производительное, напримерметод в исходном вопросе, но с использованием dicts вместо enums или с использованием метода jsbueno, однако жесткий предел на несколько порядков меньше, так что он хорошо работает для моих нужд и сохраняет разобщенность и краткость.

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