Custom thread-pooling
The function concurrent.futures.ThreadPoolExecutor.map is built into Python 3 and does almost the same thing as the code in the post. If you're still using Python 2, then there's a backport of the concurrent.futures package on PyPI.
But considered as an exercise, the code here seems basically fine (apart from the lack of documentation), and the remaining comments are minor issues.
Worker.run could be simplified slightly by writing the loop condition like this:

while not self.in_queue.empty():
    # ...

There's no need to pass a maxsize argument to the Queue constructor—the default is that the queue is unbounded, which is fine.
The only use of the workers list is to start the workers. But it would be easier to start each one as you create it:

for _ in range(num_workers):
    Worker(function, in_queue, out_queue).start()

The results come out in random(-ish) order because threads are nondeterministic. But for many use cases you would like to know which input corresponds to which output, and so you'd like the outputs to be in the same order as the inputs (as they are in the case of concurrent.futures.ThreadPoolExecutor.map).