It's happening because the return statements end the 'for' loop. It wasn't noticeable before because every number up until that point was either divisible by 2 (4,6,8) allowing the first 'if' statement in the loop to catch them or they were prime (5, 7) meaning they were taken care of in the second 'if' statement. 9 is the first number that is not a prime and is not divisible by 2.
The program doesn't show it well but what happens with your code is as follows:
9 goes into is_prime(x) as x
It isn't == 2 or == 3 so it moves on
It is greater than 2 so it moves into the 'for' loop
The first number your range checks in the 'if' statement is 2
9 realizes it isn't divisible by 2 so it moves into the 'elif'
The 'elif' is still using 2 as it's 'n' so 9 is again checked against 2, still remains not divisible and so returns true
Once the program receives a return the loop breaks, without checking any more numbers against 9
It took me about an hour to figure this out myself.
My solution was as follows
for n in range(2,x-1):
----if x%n == 0:
Using this method, if a number 'x' is applied that is cleanly divisible by any other number 'n' that is not 1 or 'x', the program returns False and then breaks. Otherwise the loop continues to iterate through the numbers until it hits the top of the range, at which point it stops, and having not run the break command, instead returns True.
Hope this helps!