Is there a template for one use of objects only?

Suppose you present some task for use with class objects Task2Do

. These objects are executable, that is, they have a method that performs a task doTask

.

On the other hand, you have a queue of these objects (example in python):

a = Task2Do(method1, args1)
b = Task2Do(method1, args2)
c = Task2Do(method2, args3)

pending = [a,b,c]

      

You want to run all tasks pending

:

for t in pending:
    t.doTask()

      

It may be that someone introduces an error so that the same object appears twice in the queue pending

:

pending = [a,a,c]

      

You can protect your code:

class Task2Do:
    def __init__(self, target, args):
        self._todo = target
        self._args = args
        self._done = False

    def doTask(self):
        if not self._done: # Protection against double execution
            self._todo(*self._args)
            self._done = True

      

My question is: Does this have a title as a design pattern? I've heard that some people have implemented something similar to calling an object's destructor in C ++.

What other similar patterns do you know?

+3


source to share


3 answers


The simplest way I can think of is this:

class Task2Do:
    def __init__(self, target, args):
        self._todo = target
        self._args = args

    def doTask(self):
        self._todo(*self._args)
        self._todo = lambda: None
        self._args = ()

      

which seems cleaner than a flag. Also, make self._todo

throws an error on the second call. You can even do this by simply setting self._todo

in None

.


To be honest, problems don't really need classes. In most cases it is simpler and more idiomatic just to have a function. In this case, you can use a one-time use generator:



def task2do(target, *args, **kwargs):
    def iter_run_once():
        yield target(*args, **kwargs)
        raise ValueError("Multiple calls to one-time-use task")

    return iter_run_once().__next__

F = task2do(print, 1, 2, 3)

F()
#>>> 1 2 3

F()
#>>> Traceback (most recent call last):
#>>>   File "", line 14, in <module>
#>>>   File "", line 4, in iter_run_once
#>>> ValueError: Multiple calls to one-time-use task

      

For fun, note that you can also do:

def task2do(target, *args, **kwargs):
    return (lambda: (yield target(*args, **kwargs)))().__next__

      

;)

+1


source


The thread pool pattern allows callable objects to be invoked into a data container and run on a dedicated set of threads. The advantage of a thread pool is that you don't have to start a thread every time you want to start an object. When the object is launched, it is removed from the container so that it does not start again. If you need additional logic to protect against running objects twice, you can add it to code where objects are added to the thread pool or to code that runs inside objects.
A good thread pool library is CTPL, https://github.com/vit-vit/ctpl .



+1


source


I don't know of a design pattern that can help here, but your Task2Do class can be simplified like this:

class Task2Do:
    def __init__(self, target, args):
        self._todo = [target]
        self._args = args

    def doTask(self):
        while len(self._todo):
            todo = self._todo.pop(0):
            todo(*self._args)

      

This avoids the penis _done

coming back to True

again.

0


source







All Articles