Here are a few different ways to do it, and their results. The performance difference is minor in the grand scheme of things, so you shouldn't worry too much.
%%timeit
for i in range(2):
for j in range(2):
for k in range(2):
value = f'{i}{j}{k}'
print(value)
Original Result: 823 µs ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
for i in range(8):
print("{0:03b}".format(i))
Result: 784 µs ± 35.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
for i in range(8):
print(bin(i)) #note that this does not produce the output exactly as you'd want it
Result: 807 µs ± 36.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
for i in range(8):
print(bin(i)[2:].rjust(3, '0')) #this one really surprised me, i didn't expect it to be fastest.
Result: 773 µs ± 43.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
And just an itertools version if you didn't want to use binary representations. Note that i have excluded library import for the sake of comparison.
from itertools import product
bits = ['0', '1']
%%timeit
for i in product(bits, repeat = 3):
print(''.join(i))
Result: 801 µs ± 65.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)