The third one is fundamentally different though. You probably know all this, but I thought it'd be a good idea to mention to prevent any confusion for other readers.
Your second example:
>>> x = ('a',)
>>> print(type(x), len(x))
<class 'tuple'> 1
>>> print(type(x[0]), x[0])
<class 'str'> a
x is now a tuple with 1 element, which is the string 'a'. (You don't need the parentheses, by the way: 'x = a,' works just as well. The comma is necessary though! Some people think tuples are created with parentheses, but parentheses are actually not required, except in the special case of the empty tuple.)
Third example:
>>> x = ('a')
>>> print(type(x), len(x))
<class 'str'> 1
x itself is now the string 'a'. The parentheses didn't change anything; you can further 'optimize' to x = a without any change in meaning. x[0] still works because, as you mention, by accident x is a string with one character. It doesn't work in other cases:
>>> x = ('gotcha')
>>> x[0]
'g'
>>> x = (3)
>>> x[0]
Traceback (most recent call last):
File "<pyshell#59>", line 1, in <module>
x[0]
TypeError: 'int' object is not subscriptable
Your second example:
x is now a tuple with 1 element, which is the string 'a'. (You don't need the parentheses, by the way: 'x = a,' works just as well. The comma is necessary though! Some people think tuples are created with parentheses, but parentheses are actually not required, except in the special case of the empty tuple.)Third example:
x itself is now the string 'a'. The parentheses didn't change anything; you can further 'optimize' to x = a without any change in meaning. x[0] still works because, as you mention, by accident x is a string with one character. It doesn't work in other cases: