Классы данных - связывание базовых методов

Я пытаюсь создать класс с двумя методами:

  • Данные запроса (как генератор)

  • Сохранить как json

    @dataclass
    class Data_Query:
        hierarchic: str
        sku: bool
        pred_lenght: int
    
        def query(self, db):
           if (self.hierarchic == 'store' and self.sku == True):
               x = db.aggregate([{...}]);
               self.export_json(x) 
    
        def export_json(self, x, file):
            with open(f'/home/Documents/dataset/{file}', 'w') as fp:
                for i in x:
                    json.dump(i, fp)
                    fp.write('\n')
    

Когда я выполняю метод запроса, выполняются оба метода.

data = Data_Query('store', True, 56)
data.query(db)

Что мне нужно изменить, чтобы эти методы назывались разделенными?

Мой ожидаемый результат:

data.query(db).export_json('abc.json')

person William    schedule 30.04.2020    source источник
comment
У вас была ошибка при идентификации. И метод запроса был выполнен методом запроса if (self.hierarchic == 'store' and self.sku == True): x = db.aggregate([{...}]); self.export_json(x) здесь   -  person ontananza    schedule 30.04.2020
comment
Нет никакой очевидной причины для того, чтобы export_json был методом Data_Query. Все необходимые данные передаются в виде двух явных аргументов.   -  person chepner    schedule 30.04.2020


Ответы (1)


Вместо того, чтобы вызывать export_json непосредственно из query, сохраните результат в атрибуте экземпляра и верните self, чтобы включить цепочку. Затем export_json ищет сохраненный запрос в экземпляре, а не принимает его в качестве аргумента.

@dataclass
class Data_Query:
    hierarchic: str
    sku: bool
    pred_lenght: int

    def query(self, db):
       if (self.hierarchic == 'store' and self.sku == True):
           self.x = db.aggregate([{...}]);
           # self.export_json(x) 
       return self

    def export_json(self, file):
        try:
            x = self.x
        except AttributeError:
            return
        
        with open(f'/home/Documents/dataset/{file}', 'w') as fp:
            for i in x:
                json.dump(i, fp)
                fp.write('\n')
        del self.x

Теперь вы можете написать data.query(db).export_json('abc.json'), и файл JSON будет записан только в том случае, если действительно выполняется запрос.

Однако это не лучший дизайн. Ничто в export_json не относится к вашему классу; это должна быть обычная функция, которая принимает результат и имя файла и которую вы вызываете после выполнения запроса, если запрос возвращает какие-либо результаты. Что-то вроде

@dataclass
class Data_Query:
    hierarchic: str
    sku: bool
    pred_lenght: int

    def query(self, db):
       if (self.hierarchic == 'store' and self.sku == True):
           return db.aggregate([{...}])

def export_json(self, x, file):
    with open(f'/home/Documents/dataset/{file}', 'w') as fp:
        for i in x:
            json.dump(i, fp)
            fp.write('\n')

result = data.query(db)
if result is not None:
    export_json(result, 'abc.json')

Вы можете возразить: «Конечно, export_json относится к моему классу; он предполагает, что x является итерируемым объектом, что определяется методом query». В этом случае вы можете подумать об определении QueryResult класса и сделать export_json методом этого класса. Затем DataQuery.query возвращает экземпляр QueryResult, и цепочка кажется немного менее произвольной: вы экспортируете результат, а не запрос.

# By the way, I am assuming there is more to this class than a query
# method; otherwise, there should probably just be a regular function
# that takes the db, hierarchic, and sku as arguments.
@dataclass
class DataQuery:
    hierarchic: str
    sku: bool
    pred_length: int

    def query(self, db):
        result = None
        if self.hierarchic == 'store' and self.sku:
            result = db.aggregate(...)
        return QueryResult(result)


class QueryResult:
    def __init__(self, result):
        self.result = result

    def export_json(self, file):
        if self.result is None:
            return

        with open(f'/home/Documents/dataset/{file}', 'w') as fp:
           for i in x:
                json.dump(i, fp)
                fp.write('\n')


data.query(db).export_json('abc.json')
person chepner    schedule 30.04.2020
comment
Большое спасибо, черт @chepner, ты мне очень помог. Последнее предложение, которое вы предложили, - это как раз мой случай. - person William; 01.05.2020