Metodo che raggruppa altri metodi della stessa famiglia e come chiamare uno di questi separatamente

0

Titolo peggiore di sempre ma non so come descrivere il mio scenario in una riga ...

Quindi ho un metodo che avvolge le chiamate di molti metodi della stessa natura. Una volta completato uno di questi metodi, è necessario chiamare un determinato aggiornamento.

class SomeClass:
    def perform_tasks():
        self.task1()
        self.task2()
        self.task3()

    def task1(self):
        # perform task 1...
        # then update
        self.update()

    def task2(self):
        # perform task 2...
        # then update
        self.update()

    def task3(self):
        # perform task 3...
        # then update
        self.update()

Poiché update viene chiamato ogni volta in quel modo, posso refactoring queste chiamate:

class SomeClass:
    def __init__(self):
        self.tasks = [self.task1, self.task2, self.task3)

    def perform_tasks():
        for task in self.tasks:
            task()
            self.update()

Forse vale la pena ricordare che SomeClass può essere ereditato in modo che le attività da eseguire possano parzialmente cambiare.

Tuttavia ora ho bisogno di chiamare alcune singole attività separatamente, e ho ancora bisogno di eseguire l'aggiornamento dopo ognuna di queste attività. Qual è il design che mi consentirà di farlo senza essere ripetitivo nel chiamare update ?

    
posta dabadaba 01.03.2018 - 14:08
fonte

1 risposta

1

Utilizza un decoratore per aggiungere facilmente update dopo ogni funzione ::

from functools import wraps


def task(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        func(self, *args, **kwargs)
        self.update()
    return wrapper


class SomeClass:
    def __init__(self):
        self.tasks = [self.task1, self.task2, self.task3]

    def perform_tasks(self):
        for task in self.tasks:
            task()
            self.update()

    def update(self):
        print('updating')

    @task
    def task1(self):
        print('perfomring task 1')

    @task
    def task2(self):
        print('perfomring task 2')

    @task
    def task3(self):
        print('perfomring task 3')

Puoi anche utilizzare il decoratore per creare l'elenco delle attività:

from functools import wraps


__next_task_idx = 0


def task(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        func(self, *args, **kwargs)
        self.update()

    global __next_task_idx
    wrapper._task_idx = __next_task_idx
    __next_task_idx += 1
    return wrapper


class SomeClass:
    def __init__(self):
        self.tasks = [getattr(self, k)
                      for k, v in type(self).__dict__.items()
                      if hasattr(v, '_task_idx')]
        self.tasks.sort(key=lambda task: task._task_idx)

    def perform_tasks(self):
        for task in self.tasks:
            task()

    def update(self):
        print('updating')

    @task
    def task1(self):
        print('perfomring task 1')

    @task
    def task2(self):
        print('perfomring task 2')

    @task
    def task3(self):
        print('perfomring task 3')

Cosa sta succedendo qui? Ho fatto ogni task con _task_idx (incrementale - quindi saranno in ordine) e nel costrutto che ho cercato (nel tipo - non saranno presenti in __dict__ dell'oggetto fino a quando non saranno chiamati), li ha raccolti in una lista e li ha ordinati (perché __dict__ dell'oggetto non è ordinato).

Il vantaggio di questo approccio è che si associa l'aggiunta di un'attività alla lista con la chiamata self.update() .

    
risposta data 01.03.2018 - 14:43
fonte