The code in the recipe defines two methods. They are normal Python methods, having self as their first argument, and can have additional arguments as well. The methods are decorated with decorators from the odoo.api module.
When writing a new method, you will generally use @api.multi. This decorator indicates that the method is meant to be executed on a recordset. In such methods, self is a recordset that can refer to an arbitrary number of database records (this includes empty recordsets), and the code will often loop over the records in self to do something on each individual record.
The @api.model decorator is similar, but it's used on methods for which only the model is important, not the contents of the recordset, which is not acted upon by the method. The concept is similar to Python's @classmethod decorator.
Here's an example code snippet calling the change_state() method from the recipe:
# returned_book_ids is a list of book ids to return books = self.env['library.book'] books.browse(returned_book_ids).change_state('available')
When change_state() is called, self is a (possibly empty) recordset containing records of the library.book model. The body of the change_state() method loops over self to process each book in the recordset. Looping on self looks strange at first, but you will get used to this pattern very quickly.
Inside the loop, change_state() calls is_allowed_transition(). The call is made using the book local variable, but it can be made on any recordset for the library.book model, including, for example, self, since is_allowed_transition() is decorated with @api.model. If the transition is allowed, change_state() assigns the new state to the book by assigning a value to the attribute of the recordset. This is only valid on recordsets of length 1, which is guaranteed to be the case when iterating over self.