Place value
In 173 each digit's place sets its worth: 1 hundred, 7 tens and 3 ones. Moving one place left multiplies the worth by 10. Add digit × place: 100 + 70 + 3 = 173.
Binary, or base 2, has only two digits, 0 and 1, called bits. Each place is worth twice the one to its right: 1, 2, 4, 8, 16, 32, 64, 128. Eight bits make a byte.
Decimal to binary
To write 173 in binary, divide by 2 and keep the remainder: 173 ÷ 2 = 86, remainder 1. That 1 is the ones bit. Repeat with 86, then 43, until you reach 0. The bits fill in from the right: 10101101.
Check it with place values. Add the places that hold a 1: 128 + 32 + 8 + 4 + 1 = 173. The places holding 0 add nothing. Same number, new spelling: 10101101 in base 2.
Inside a chip, each bit is a wire at a high or a low voltage, like a switch that is on or off. Two states are easy to tell apart even when the signal is noisy, so computers store every number as bits.
Hex and octal
Hexadecimal is base 16. It counts 0 to 9, then A to F for 10 to 15. Four bits have exactly 16 patterns, so each group of four bits becomes one hex digit: 1010 is A and 1101 is D.
Hex places grow by 16: the ones place, then 16, then 256. So AD means A × 16 + D × 1. With A = 10 and D = 13, that is 160 + 13 = 173. Two hex digits describe one byte.
Octal is base 8, with digits 0 to 7. Three bits make one octal digit, so group the bits in threes from the right: 10 101 101 gives 2, 5, 5. Python writes it 0o255. Today octal shows up mostly in Unix file permissions.
In code
Turn all eight bits on: 11111111. In hex each group 1111 is F, so it is FF, written 0xFF in code. F × 16 + F = 15 × 16 + 15 = 255, the largest number one byte can hold.
Python's int() reads text written in any base: int('ad', 16) gives 173, and so does int('10101101', 2). One value, many spellings. Programmers like hex because it is short and maps neatly onto bits.
Try it in the Python prompt
;; step 1/10 · Base 10: place value >>> 1*100 + 7*10 + 3*1 173 >>> 10**2, 10**1, 10**0 # the decimal places (100, 10, 1)
Repeated division works for any base: divide by the base, keep the remainder, and repeat with the quotient until it is 0. The remainders, read from the last one to the first, are the digits. Python prints hex digits in lower case ('0xad'); 0xAD and 0xad are the same number. 0b, 0o and 0x are prefixes that say which base a literal is written in.