Question: I have a class within a class and want to activate threading capabilities in the second class. Essentially, the script below is a reproducible template of my proper project. When I use @threading I get that showit is not iterable, so the tp.map thinks I do not have a list. However, when I run: if __name__ == '__main__': tp = ThreadPoolExecutor(5) print(tp.map(testit(id_str).test_first, id_int)) for values in tp.map(testit(id_str).test_first, id_int): values  I get no issues, besides that I want the expected output to print out each number in the list. However, I wanted to achieve this within the class. Something like the following: from concurrent.futures import ThreadPoolExecutor from typing import List id_str = ['1', '2', '3', '4', '5'] id_int = [1, 2, 3, 4, 5] def threaded(fn, pools=10): tp = ThreadPoolExecutor(pools) def wrapper(*args): return tp.map(fn, *args) # returns Future object return wrapper class testit: def __init__(self, some_list: List[str]) -> None: self._ids = some_list print(self._ids) def test_first(self, some_id: List[int]) -> None: print(some_id) class showit(testit): def __init__(self, *args): super(showit, self).__init__(*args) @threaded def again(self): global id_int for values in self.test_first(id_int): print(values) a = showit(id_str) print(a.again())  Error:  File "test_1.py", line 32, in <module> print(a.again()) File "test_1.py", line 10, in wrapper return tp.map(fn, *args) # returns Future object File "/Users/usr/opt/anaconda3/lib/python3.8/concurrent/futures/_base.py", line 600, in map fs = [self.submit(fn, *args) for args in zip(*iterables)] TypeError: 'showit' object is not iterable  Expected output: 1 2 3 4 5 

Answer: Considerations:  Writing a decorator that takes an optional argument needs to be done a bit differently than the way you have done it. I am assuming you would like the threaded decorator to be able to support both functions and methods if that is not to difficult to accomplish.  The decorated function/method can take as many positional and keyword arguments as you want (but at least one positional argument). When you call the wrapped function the last positional argument must be an iterable that will be used with the pool's map method. All positional and keyword arguments will then be passed to the function/method when it is invoked as a worker function by map except that the last positional argument will now be an element of the iterable. from concurrent.futures import ThreadPoolExecutor from functools import wraps, partial def threaded(poolsize=10): def outer_wrapper(fn): wraps(fn) def wrapper(*args, **kwargs): """ When the wrapper function is called, the last positional argument iterable will be an iterable to be used with the pool's map method. Then when map is invoking the original unwrapped function/method as a worker function, the last positional argument will be an element of that iterable. """ # We are being called with an iterable as the first argument" # Construct a worker function if necessary: with ThreadPoolExecutor(poolsize) as executor: worker = partial(fn, *args[:-1], **kwargs) return list(executor.map(worker, args[-1])) return wrapper return outer_wrapper iterable = [1, 2, 3] @threaded(len(iterable)) def worker1(x, y, z=0): """ y, the last positional argument, will be an iterable when the wrapper function is called or an element of the iterable when the actual, unwrapped function, worker1, is called. """ return x + (y ** 2) - z @threaded(3) def worker2(x): return x.upper() class MyClass: @threaded() def foo(self, x): return -x # last positional argument is the iterable: print(worker1(100, iterable, z=10)) print(worker2(['abcdef', 'ghijk', 'lmn'])) o = MyClass() print(o.foo([3, 2, 1]))  Prints: [91, 94, 99] ['ABCDEF', 'GHIJK', 'LMN'] [-3, -2, -1]