One possible solution for the cnoder would be to simply iterate over the string and count the character occurences, not very fancy but O(n).
def encode(s):
last = s[0]
count = 0
for c in s:
if last != c:
yield '%s%i' % (last, count)
last = c
count = 0
count += 1
yield '%s%i' % (last, count)
For the decoder you could use a regular expression which splits the string up nicely for you, no need to write your own parser.
import re
def decode(s):
for c, n in re.findall(r'(\w)(\d+)', s):
yield c * int(n)
given your test input
s = 'AAABBBBCDDDDDDDDDDEEDDDD'
encoded = ''.join(encode(s))
print encoded
decoded = ''.join(decode(encoded))
print decoded
results in
A3B4C1D10E2D4
AAABBBBCDDDDDDDDDDEEDDDD
One more note, there's no real reason to use yield here, you could of course also build the strings in the en-/decode functions first, then return.