The last implementation is the best, because it introduces semantics (you can check whether something is a cons cell with type(x) is cons; in other words you can implement pair?, which can be done in the second version but you have to check the func_code.co_code), and because you can use it with either the car and cdr functions, or the car and cdr properties.