Acontece que literais de strings são cacheados pra ocupar menos espaço na memória. É um detalhe de implementação. Outras linguagens fazem isso também, tipo Java. Um outro ponto interessante é que, dependendo do interpretador que você tá usando, só strings com caracteres alfanuméricos e underline são cacheados. Se quiser testar, coloca uma exclamação na string e vê se ainda retorna True
Antes de criar um novo objeto pra segunda string, o interpretador vê se já existe alguma string igual criada anteriormente. Se tiver, ele usa o mesmo objeto. É por isso que o is retorna True.
>>> a = '#!@#!#%@#%'
>>> b = '#!@#!#%@#%'
>>> a is b
False
Então, primeiro você precisa entender que tudo no Python são objetos, absolutamente tudo. O operador == compara se dois objetos tem os mesmo valores, i.e., se eles são iguais; já o operador is compara se “dois objetos” são na verdade o mesmo objeto, i.e., se eles apontam para o mesmo lugar na memória, se eles têm o mesmo id().
a = "abcd"
b = "abcd"
c = a
print(a == b) #True
print(id(a))
print(id(b))
print(id(c))
print(a is b) #False
print(a is c) #True
Como podes ver, uma vez que dois objetos têm o mesmo id() o is retorna True.