I'd like some clarification on the way the str.join()
method works when passed a tuple.
Take for example this code snippet:
a = ("A", "B")
print(''.join(a))
This gives expected output: AB
So from this I ascertained that passing join an iterable (Such as a tuple) would allow it to unpack and "join" the contents together.
With this knowledge in mind I wrote the following generator expression:
import random
import string
generated_string = ''.join((random.choice(string.ascii_letters), random.choice(string.digits)) for _ in range(4))
This results in the following error:
Traceback (most recent call last):
File "main.py", line 5, in <module>
generated_string = ''.join((random.choice(string.ascii_letters), random.choice(string.digits)) for _ in range(4))
TypeError: sequence item 0: expected str instance, tuple found
I'm confused as to why this isn't working. I can manually iterate through the contents of the generator and "join" the tuples manually, for example:
generated_string = ((random.choice(string.ascii_letters), random.choice(string.digits)) for _ in range(4))
for val in generated_string:
print(''.join(val))
Which gives the following output:
U7
W1
y7
G8
What am I missing here? It feels like it's obvious but I feel like I've covered all bases.
Thank you for your time.
As you said, you pass an iterable to join
, and the items must be strings. The iterable can be a tuple, generator, list, or whatever. However:
''.join((random.choice(string.ascii_letters), random.choice(string.digits)) for _ in range(4))
That's not a tuple of strings, it's a sequence of tuples of strings.
print(list((random.choice(string.ascii_letters), random.choice(string.digits)) for _ in range(4)))
# [('w', '7'), ('X', '6'), ('W', '7'), ('P', '1')]
Edit: To fix it you can either nest two ''.join
like so:
''.join(''.join((random.choice(string.ascii_letters), random.choice(string.digits))) for _ in range(4))
or, since you know you're always joining exactly two items, use an f-string:
''.join(f'{random.choice(string.ascii_letters)}{random.choice(string.digits)}' for _ in range(4))