j0kky
j0kky

Reputation: 85

Using class attribute in concurrent.futures threads

How can I use some class attribute within a thread that calls other methods without editing the initial value and without passing the attribute as a parameter?

"First" and "second" value must always be equal to "init" value, and "third" and "fourth" must be both equal.

This example shows the initial problem:

from concurrent.futures import ThreadPoolExecutor
from random import random
from time import sleep

class main():
    def __init__(self):
        self.var = random()
        print('init', self.var)

    def first(self):
        print('first', self.var)
        self.second()
        print('fourth', self.var)

    def second(self):
        print('second', self.var)
        self.var = random()
        print('third', self.var)
        sleep(1)

m = main()
with ThreadPoolExecutor() as executor:
    executor.submit(m.first)
    executor.submit(m.first)
    executor.submit(m.first)

Assigning self.var to another attribute withing the method doesn't obviously work:

class main():
    def __init__(self):
         self.var = random()
         print('init', self.var)

    def first(self):
         self.var2 = self.var
         print('first', self.var2)
         self.second()
         print('fourth', self.var2)

    def second(self):
        print('second', self.var2)
        self.var2 = random()
        print('third', self.var2)
        sleep(1)

The only solution I tried is assigning the attribute to a local variable and passing it to the called function as a parameter. This is not a good solution in my case because I need to pass lots of attributes and the code rapidly increase and begin less readable.

class main():
    def __init__(self):
        self.var = random()
        print('init', self.var)

    def first(self):
        var = self.var
        print('first', var)
        var = self.second(var)
        print('fourth', var)

    def second(self, par):
        print('second', par)
        par = random()
        print('third', par)
        sleep(1)
        return par

Can you think of a pythonic way to use the attribute instead of the local variable passed as parameter?

EDIT: I've just found out a new way to face the problem: using "nonlocal" statement and nesting the functions, what do you think about it?

class main():
def __init__(self):
    self.var = random()
    print('init', self.var)

def first(self):
    var = self.var
    print('first', var)

    def second():
        nonlocal var
        print('second', var)
        var = random()
        print('third', var)
        sleep(1)

    second()
    print('fourth', var)

Upvotes: 1

Views: 3659

Answers (1)

Borys Serebrov
Borys Serebrov

Reputation: 16172

If you just want to have separate state for each tread, you can create and pass different objects into each thread:

from concurrent.futures import ThreadPoolExecutor
from random import random
from time import sleep

class main():
    def __init__(self):
        self.var = random()
        print('init', self.var)

    def first(self):
        print('first', self.var)
        self.second()
        print('fourth', self.var)

    def second(self):
        print('second', self.var)
        self.var = random()
        print('third', self.var)
        sleep(1)

def worker():
    m = main()
    m.first()

with ThreadPoolExecutor() as executor:
    executor.submit(worker)
    executor.submit(worker)
    executor.submit(worker)

Upvotes: 3

Related Questions