473,545 Members | 2,043 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Block-structured resource handling via decorators

When handling resources in Python, where the scope of the resource is
known, there seem to be two schools of thought:

(1) Explicit:
f = open(fname)
try:
# ...
finally:
f.close()

(2) Implicit: let the GC handle it.

I've come up with a third method that uses decorators to achieve a
useful mix between the two. The scope of the resource is clear when
reading the code (useful if the resource is only needed in part of a
function), while one does not have to write an explicit cleanup. A
couple of examples:

@withFile(fname , 'w')
def do(f):
# ... write stuff into file f ...

@withLock(aLock ):
def do():
# ... whatever you needed to do once the lock was acquired,
# safe in the knowledge it will be released afterwards ...

(The name "do" is arbitrary; this method has the "mostly harmless"
side-effect of assigning None to a local variable with the function
name.)

I find it clear because I come from a C++/C#/Java background, and I
found C#'s using-blocks to very useful, compared to the explicit
finallys of Java. I know that Python's deterministic finalization sort
of achieves the same effect, but I had been led to believe there were
complications in the face of exceptions.

The implementation is easily extensible: a handler for a new type of
resource can be written in as a couple of lines. For the examples above:

class withFile(blockS copedResource):
init, cleanup = open, 'close'

It's so simple I was wondering why I haven't seen it before. Possibly:
it's a stupid idea and I just can't see why;
everyone knows about it except me;
it's counter-intuitive (that's not the way decorators were intended);
it's "writing C# in Python" or in some other way unPythonic;
I've actually had an idea that is both Original and non-Dumb.

If the last is the case, can someone let me know, and I'll put up the
code and explain how it all works. On the other hand, if there is
something wrong with it, please can someone tell me what it is?

Thanks

John Perks
Jul 29 '05 #1
5 1715
John Perks:
When handling resources in Python, where the scope of the resource is
known, there seem to be two schools of thought:
...


This is part of what PEP 343 addresses:
http://www.python.org/peps/pep-0343.html

Neil
Jul 30 '05 #2
"John Perks and Sarah Mount" <jo**********@e stragon.freeser ve.co.uk> writes:
When handling resources in Python, where the scope of the resource is
known, there seem to be two schools of thought:

(1) Explicit:
f = open(fname)
try:
# ...
finally:
f.close()

(2) Implicit: let the GC handle it.
The only cases I see the first school of thought is when the resource
in question is "scarce" in some way. For example, most OS's place a
limit on the number of open files a process can have, some rather
tight. CPython's garbage collector will close an open file when it
leaves scope. Jython's GC will close it when the file is collected,
but you have no idea of when that will be, and an "open" failing won't
trigger a GC. So in this case, the first form is less likely to fail
unexpectedly.
I've come up with a third method that uses decorators to achieve a
useful mix between the two. The scope of the resource is clear when
reading the code (useful if the resource is only needed in part of a
function), while one does not have to write an explicit cleanup. A
couple of examples:

@withFile(fname , 'w')
def do(f):
# ... write stuff into file f ...

@withLock(aLock ):
def do():
# ... whatever you needed to do once the lock was acquired,
# safe in the knowledge it will be released afterwards ...

The implementation is easily extensible: a handler for a new type of
resource can be written in as a couple of lines. For the examples above:

class withFile(blockS copedResource):
init, cleanup = open, 'close'

It's so simple I was wondering why I haven't seen it before. Possibly:
it's a stupid idea and I just can't see why;
everyone knows about it except me;
it's counter-intuitive (that's not the way decorators were intended);
it's "writing C# in Python" or in some other way unPythonic;
I've actually had an idea that is both Original and non-Dumb.


Well, I'd say that using a string for cleanup and a function for init
is unpythonic. But the general idea seems to be a good one. Making it
easy to deal with resources that must be explicitly released is a good
thing. The question is whether having to turn your scope into a
function to do this is more trouble than it's worth.

I'd certainly be interested in seeing the implementation.

<mike
--
Mike Meyer <mw*@mired.or g> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 30 '05 #3
Mike Meyer <mw*@mired.or g> writes:
When handling resources in Python, where the scope of the resource is
known, there seem to be two schools of thought:
(1) Explicit: ...
(2) Implicit: let the GC handle it.


The only cases I see the first school of thought is when the resource
in question is "scarce" in some way. For example, most OS's place a
limit on the number of open files a process can have, some rather
tight. CPython's garbage collector will close an open file when it
leaves scope. Jython's GC will close it when the file is collected,
but you have no idea of when that will be, and an "open" failing won't
trigger a GC. So in this case, the first form is less likely to fail
unexpectedly.


I thought there was a Zen thing somewhere saying that Python is not
Perl. One of Perl's silliest tenets is that the implementation
defines the language. There are already 4 different Python
implementations (CPython, Jython, Pypy, IronPython) and probably more
on the way. We should take the view that the manual, not the
implementation, defines the language.

The manual doesn't specify anything about reference counting or GC
happening as soon as something goes out of scope. That is a GOOD
thing since requiring CPython-like behavior would eliminate many good
GC techniques, including some that are both more efficient and easier
for extension writers to deal with. Since reference counting is not
in the manual, it is not part of the language, it's subject to change
at any time in any implementation, and non-throwaway Python apps
should not depend on it.

On the other hand, the try/finally explicit release is cumbersome and
non-tasty.

Therefore, the correct solution is a language extension along the
lines of PEP 343. I haven't studied PEP 343 specifically enough to
say that I think every detail of it is the right thing, but at least
it is the right idea.

Jul 30 '05 #4
I will shamelessly point out my decorator module:
http://www.phyast.pitt.edu/~micheles.../decorator.zip

The documentation is here:
http://www.phyast.pitt.edu/~micheles...umentation.htm

There is an example of redirecting stdout which is
relevant to this thread.
HTH,

Michele Simionato

Jul 30 '05 #5
> The only cases I see the first school of thought is when the resource
in question is "scarce" in some way.
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
class withFile(blockS copedResource):
init, cleanup = open, 'close'

Well, I'd say that using a string for cleanup and a function for init
is unpythonic.


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.
The question is whether having to turn your scope into a
function to do this is more trouble than it's worth.
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.

I'd certainly be interested in seeing the implementation.


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 blockScopedReso urce(object):
def __init__(self, init, cleanup,
initArgs, initKwargs, cleanupArgs, cleanupKwargs,
passResource, resourceIsFirst Arg):

self.init = init # function to get resource
self.cleanup = cleanup # function to release resource
self.initArgs, self.initKwargs = initArgs, initKwargs
self.cleanupArg s, self.cleanupKwa rgs = cleanupArgs,
cleanupKwargs
self.passResour ce = passResource # whether resource is passed
into block
self.resourceIs FirstArg = resourceIsFirst Arg # whether resource
is arg to init,
# rather than returned from it

def __call__(self, block):
resource = self.init(*self .initArgs, **self.initKwar gs)
if self.resourceIs FirstArg:
resource = self.initArgs[0]

try:
if self.passResour ce:
block(resource)
else:
block()
finally:
self.cleanup(re source, *self.cleanupAr gs,
**self.cleanupK wargs)

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.MethodTyp e) and f.im_self is None:
f = f.im_func
if not isinstance(f, basestring): return f
def helper(resource , *args, **kwargs):
return getattr(resourc e, str(f))(*args, **kwargs)
return helper

class simpleResource( blockScopedReso urce):
def __init__(self, *initArgs, **initKwargs):
# get attributes off type
t = type(self)
blockScopedReso urce.__init__(s elf,
stringToMethod( t.init), stringToMethod( t.cleanup),
initArgs, initKwargs, t.cleanupArgs, t.cleanupKwargs ,
t.passResource, t.resourceIsFir stArg)

# defaults supplied here
cleanupArgs, cleanupKwargs = (), {}
passResource = True
resourceIsFirst Arg = False
Then useful implementations can be written by:

class withFile(simple Resource):
init, cleanup = open, 'close'

class withLock(simple Resource):
init, cleanup = 'acquire', 'release'
passResource = False
resourceIsFirst Arg = 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:doSomet hing(withAnArg) )

Gotcha: If you stack multiple resource-decorator it won't do what you
want:

# !!! DOESN'T WORK !!!
@withLock(aLock )
@withLock(anoth erLock)
def do():
# ...

Either nest them explicitly (causing your code you drift ever further to
the right):
@withLock(aLock )
def do():
@withLock(anoth erLock)
def do():
# ...

Or come up with a multiple-resource handler, which shouldn't be too
hard:

@withResources( withLock(aLock) , withLock(anothe rLock),
withFile('/dev/null'))

But I'll get round to that another day.


Jul 30 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

699
33348
by: mike420 | last post by:
I think everyone who used Python will agree that its syntax is the best thing going for it. It is very readable and easy for everyone to learn. But, Python does not a have very good macro capabilities, unfortunately. I'd like to know if it may be possible to add a powerful macro system to Python, while keeping its amazing syntax, and if it...
4
2645
by: Christopher | last post by:
This should be a quick one. URL: http://cfa-www.harvard.edu/~cpilman/Stuff/flush.html Code: ============================= <!DOCTYPE HTML Public "-//W3C//DTD HTML 4.01//EN"> <HTML><Head><Title>Get my feet off the ground</Title> <Meta HTTP-Equiv="Content-Type" Content="text/html; charset=us-ascii"> <Style type="text/css"> Body { font-size:...
2
2206
by: TadPole | last post by:
Hi all, My main problems are::::::::: 1. Set a value within a block container that can be used and changed by subsequent templates/block-containers/tables etc.. 2. get/determine/find the setting that tell the process that the new top of the document region is now at the end of the last block-container used, this must be set in that last...
7
7698
by: seamoon | last post by:
Hi, I'm doing a simple compiler with C as a target language. My language uses the possibility to declare variables anywhere in a block with scope to the end of the block. As I remembered it this would be easily translated to C, but it seems variable declaration is only possible in the beginning of a block in C. Any suggestions how to get...
6
787
by: ste.paoletti | last post by:
hi, I have read that browsers support block element inside inline element but the css is not valid. Someone can tell me more about? What do you think? Thanks.
2
2506
by: morrell | last post by:
I have a request to find out is there an easy way to solve this little poblem. ___________________ | Block 1 | | | | | | | |__________________|
8
3314
by: Alvin | last post by:
I'm making a very simple game in SDL, and I'm not asking for SDL help I hope - this looks like something C++ related, so I'll ask here. I have a class for a simple block, or tile, in the game, which can be either on or off. I'm having trouble with the constructor though. class block { private: SDL_Surface *screen;
6
2011
by: dave8421 | last post by:
Hi, I'm a bit confused about the definition about "Prinicpal Block Boxes" in CSS 2.1 draft specification. ( http://www.w3.org/TR/2006/WD-CSS21-20061106 ) <pre> 9.2.1 Block-level elements and block boxes The principal block box establishes the containing block for descendant boxes and generated
2
2028
by: Bob Greschke | last post by:
This is the idea Block = pack("240s", "") Block = pack(">H", W) Block = pack(">H", X) Block = pack(">B", Y) Block = pack(">H", Z)) but, of course, Block, a str, can't be sliced. The real use of this is a bit more complicated such that I can't just fill in all of the "fields"
15
3134
by: cssExp | last post by:
hello, Rather than going on a wild explanation on what's the the problem, it'll be much quicker and easier if i let you look at it yourself, so I'll post my page source (actual contents taken out, of course). <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html...
0
7468
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7401
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7656
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
1
5329
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
4945
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3450
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
1884
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1014
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
704
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.