As far as the last colon is concerned, I'm not sure why x = bank(): is written that way. As has been suggested, it's probably a mistake.
In the example, if x = Bank() is executed, x is an instance of the Bank class, or a Bank object. This object has a copy of the function that is defined below, which all Bank objects should have:
def create_atm(self):
while not self.crisis:
yield "$100"
The line before the function defines crisis as being False. Here crisis is an internal variable or a property which by default has a value False. This is important to answer your next question:
So, since crisis = False so does the create_atm function basically say while crisis = true yield $100?
while statements are only executed when the condition tested is True. In this case the condition is not self.crisis, the opposite of whatever is in self.crisis. So you need to look at the value of crisis that this Bank sees in itself, and negate that.
If self.crisis is True then not self.crisis would be False and the while loop will not even execute.
I guess you could say self is a parameter passed to the function so that it can access its own variables. That way, one Bank could be in crisis while another is not.