Forums
New posts
Search forums
Members
Current visitors
Log in
Register
What's new
Search
Search
Search titles only
By:
New posts
Search forums
Menu
Log in
Register
Install the app
Install
Forums
Archive
Archive
Python
Block-structured resource handling via decorators
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
[QUOTE="John Perks and Sarah Mount, post: 1830943"] The only cases I see the first school of thought is when the resource By "resource" I meant anything with some sort of acquire/release semantics. There may be plenty of threading.Locks available, but it's still important that a given Lock is released when not needed. For example, most OS's place a I could have specified cleanup as lambda f:f.close(), but as I thought it might be quite common to call a method on the resourse for cleanup, if a string is specified a method of that name is used instead. Needing one slightly contrived-looking line (the def) vs a try-finally block with explicit cleanup code? I know which I'd prefer, but for all I know I could in a minority of 1 here. And so you shall... I start with the base class. It does all the work, everything else is just tweaks for convenience. Normally, then, you wouldn't need to bother with all the __init__ params. class blockScopedResource(object): def __init__(self, init, cleanup, initArgs, initKwargs, cleanupArgs, cleanupKwargs, passResource, resourceIsFirstArg): self.init = init # function to get resource self.cleanup = cleanup # function to release resource self.initArgs, self.initKwargs = initArgs, initKwargs self.cleanupArgs, self.cleanupKwargs = cleanupArgs, cleanupKwargs self.passResource = passResource # whether resource is passed into block self.resourceIsFirstArg = resourceIsFirstArg # whether resource is arg to init, # rather than returned from it def __call__(self, block): resource = self.init(*self.initArgs, **self.initKwargs) if self.resourceIsFirstArg: resource = self.initArgs[0] try: if self.passResource: block(resource) else: block() finally: self.cleanup(resource, *self.cleanupArgs, **self.cleanupKwargs) But this still won't do conveniently for files and locks, which are my motivating examples. The simpleResource class constructor gets its setup from attributes on the type of the object being created, with sensible defaults being set on simpleResource itself. As stated above, if a string is supplied as init or cleanup, it is treated as a method name and that method is used instead. def stringToMethod(f): # Getting the attribute from the class may have wrapped it into # an unbound method; in this case, unwrap it if isinstance(f, types.MethodType) and f.im_self is None: f = f.im_func if not isinstance(f, basestring): return f def helper(resource, *args, **kwargs): return getattr(resource, str(f))(*args, **kwargs) return helper class simpleResource(blockScopedResource): def __init__(self, *initArgs, **initKwargs): # get attributes off type t = type(self) blockScopedResource.__init__(self, stringToMethod(t.init), stringToMethod(t.cleanup), initArgs, initKwargs, t.cleanupArgs, t.cleanupKwargs, t.passResource, t.resourceIsFirstArg) # defaults supplied here cleanupArgs, cleanupKwargs = (), {} passResource = True resourceIsFirstArg = False Then useful implementations can be written by: class withFile(simpleResource): init, cleanup = open, 'close' class withLock(simpleResource): init, cleanup = 'acquire', 'release' passResource = False resourceIsFirstArg = True And new ones can be created with a similar amount of effort. Of course, one-liners can be done without using the decorator syntax: withLock(aLock)(lambda:doSomething(withAnArg)) Gotcha: If you stack multiple resource-decorator it won't do what you want: # !!! DOESN'T WORK !!! @withLock(aLock) @withLock(anotherLock) def do(): # ... Either nest them explicitly (causing your code you drift ever further to the right): @withLock(aLock) def do(): @withLock(anotherLock) def do(): # ... Or come up with a multiple-resource handler, which shouldn't be too hard: @withResources(withLock(aLock), withLock(anotherLock), withFile('/dev/null')) But I'll get round to that another day. [/QUOTE]
Verification
Post reply
Forums
Archive
Archive
Python
Block-structured resource handling via decorators
Top