It has to do with the way an integer is stored in binary.
& is a bit-operator which is an AND gate for the bits left and right of it. And works like this for two bits:
1 & 1 => 1
1 & 0 => 0
0 & 1 => 0
0 & 0 => 0
Due to the binary representation every power of 2 is represented with a 1 at a position i and all zeroes on all positions < i. Because of that and the way AND works we only get a 1 bit if we have 1 at both positions left and right. So for every power of two we have a single 1 and the rest all zeroes and for every value that is not a power of two will use <= i-1 bits, at least one of which is different from zero.
The result of the operation n & (n - 1), if we have a power of two power_of_two & power_of_two - 1, will always return 0 which is a falsy value in Python so the else branch will be triggered. For every value that is not a power of two not_power_of_two & not_power_of_two - 1 will return something != 0 which is a truthy value in Python hence "NO" is returned.
Probably this example is easier to understand that all the text above:
| Input | Binary repr. input | Binary repr. input -1 | Result AND (&) binary | Result AND decimal | Python truthy/ falsy | 
| 0 | 0b0000 | 0b1111 | 0b0000 | 0 | falsy | 
| 1 | 0b0001 | 0b0000 | 0b0000 | 0 | falsy | 
| 2 | 0b0010 | 0b0001 | 0b0000 | 0 | falsy | 
| 3 | 0b0011 | 0b0010 | 0b0010 | 2 | truthy | 
| 4 | 0b0100 | 0b0011 | 0b0000 | 0 | falsy |