So, I'm trying to understand the math involved when trying to translate hexadecimal escape sequences into integers.
So if I have the string "Ã", when I do "Ã".encode('utf-8') I get a byte string like this "\xc3". ord("Ã") is 195. The math is 16*12+3 which is 195. Things makes sense.
But if I have the character "é" - then the utf8-encoded hex escape sequence is "\xc3\xa9 - and ord("é") is 233. How is this calculation performed? (a9 on its own is 169 so it's clearly not addition).
Similarly with this 'Ĭ'.encode('utf-8'). This yields b'\xc4\xac'. And ord('Ĭ') is 300.
Can anyone explain the math involved here?
So, I thought I'd just wrap this one up and post the answers to the math issues I didn't comprehend before receiving a tons of wisdom from SO.
The first question regarded "é" which yields "\xc3\xa9" when encoded with utf8 and where ord("é") returns 233. Clearly 233 was not the sum of 195 (decimal representation of c3) and 169 (ditto for a9). So what's going on?
"é" is has the corresponding unicode point U+00E9. The decimal value for the hex e9 is 233. So that's what the ord("é") is all about.
So how does this end up as "\xc3\xa9"?
As Jörg W Mittag explained and demonstrated, in utf8 all non-ASCII are "encoded as a multi-octet sequence".
The binary representation of 233 is 11101001. As this is non-ASCII this needs to be packed in a two-octet sequence which according to Jörg will follow this pattern:
110xxxxx 10xxxxxx (110 and 10 are fixed leaving room for five bits in the first octet, and six bits in the second - 11 in total). 
So the 8 bits binary representation of 233 is fitted into this pattern replacing the xx-parts... Since there are 11 bits available and we only need 8 bits we pad the 8 bits with 3 more, 000, (i.e. 00011101001).
^^^00011 ^^101001 (000 followed by our 8 bits representation of 233)
11000011 10101001 (binary representation of 233 inserted in a two-octet sequence)
11000011 equals the hex c3, as 10101001 equals a9- which in other words matches the original sequence "\xc3\xa9"
A similar walkthrough for the character "Ĭ":
'Ĭ'.encode('utf-8') yields b'\xc4\xac'. And ord('Ĭ') is 300.
So again the unicode point for this character is U+012C which has the decimal value of 300 ((1*16*16)+(2*16*1)+(12*1)) - so that's the ord-part.
Again the binary representation of 300 is 9 bits, 100101100. So once more there's a need for a two-octet sequence of the pattern 110xxxxx 10xxxxxx. And again we pad it with a couple of 0 so reach 11 bits (00100101100).
^^^00100 ^^101100 (00 followed by our 9 bits representation of 300)
11000100 10101100 (binary representation of 300 inserted in a two octet-sequence).
11000100 corresponds to c4in hex, 10101100 to ac - in other words b'\xc4\xac'.
Thank you everyone for helping out on this. I learned a lot.
How to calculate integer based on byte sequence