User login |
Python methods are not python functionsAs much as python treats functions as first order objects analogous in most ways to any other new-style object, it is important to observe the fine differences between methods and functions, and in the process hopefully avoid a few edge case pitfalls.
Some fun facts to keep in mind: * Methods are of two types: bound and unbound. The unbound type is the form of the method given to the class definition. * class method declarations decorated @staticmethod are actually functions, and not unbound methods at all. This makes sense in thinking about, but is sometimes easy to forget. * Class methods use their closure when they are 'bound' to a class instance. As a result, a bound method is actually a reference to the unbound method of the class it is inheritted from, and the closure is the only instance-specific piece. This is a nice obvious optimization. *As a result of the previous, bound class methods are python types that do not possess, as functions do, modifiable dicts/closures.
Why would the last fact make much a difference? Well, imagine you have a function that takes as an argument, a callable-object 'f'. Now imagine that you might want to keep some state between multiple calls to this function for the same callable f. As long as f is an object implementing __call__ or a function, this works like a champ:
def blackbox(f): state = getattr(f, '_mystate', None) # Do some stuff with the state ... f._mystate = state
One imaginable scenario (and in fact, a scenario I recently implemented) was some utility function that would take a callable and a timeout. If my utility function was not called with the same callable within timeout time, it would call the callable. If it was, it would just, as per definition, wait until the provided time out for another call ot itself, or else finally call the callable. This was used to notify a callback only when a keystroke event was not recorded for some amount of time.
This solution is nice for its simplicity, but unfortunately does not work on instance methods. It would be nice to believe that instance methods were their own function objects shared for that instance, and could have their dict manipulated directly, but because of the above optimization, this does not work. There are a number of possible work arounds. I could use a dictionary to map a callable to it's state; this would work for methods and functions and __call__ objects alike. The biggest problem with this is that it imposes the restriction that every callable implement __hash__, which isn't always possible. The other solution is to provide, as another required argument, a state object of your own to be used. This works, but takes alot of the usefulness and work out of our utility function and imposes responsibility on its user to manage the relationship between state objects and the callables passed in.
Actually, there are a few more interesting work arounds, but none of them reach the real grace of methods having their own modifiable dict. So you were hoping I had a good solution? No, not really any better one than you may come up on your own ;) But, just letting you know, to avoid pitfalls of this kind in the future. Maybe if I come up with a single convincing solution, I will post it. For now, we must accept optimizations in the name of python not being DOG slow. And really, I fully admit, this situation is pretty niche.
|
NTT Related News
|