This is because of how and and or operators evaluate in Python.
From documentation -
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
They do not return True or False , they return the last evaluated value , and that is why we can write things like -
s = s or "Some default value"
To default the value of s if its None or empty string or empty list, or 0.
Basically, or returns the first non false-like value ( where false-like values are 0, or None or Empty string/list/tuple, etc ) Or the last false-like value if all the values are false-like. Example -
In [1]: 0 or 10
Out[1]: 10
In [2]: 5 or 0 or 10
Out[2]: 5
In [7]: 0 or '' or [] or ()
Out[7]: ()
And, and returns the first false-like value, or the last true-like value , if all the values are true-like. Example -
In [3]: 0 and 10
Out[3]: 0
In [4]: 5 and 10
Out[4]: 10
In [6]: 5 and 0 and 10
Out[6]: 0
In your case, it works as -
if y is 0 it returns x (irrespective of the value of x) .
otherwise it computes gcd(y, x%y) if that is non-zero returns it. (Though it would never really be 0)
if the result of gcd(y, x%y) is 0, then it returns x .