[Python-Dev] PEP 340: Examples as class's.

Ron Adam rrr at ronadam.com
Fri May 6 02:12:36 CEST 2005


Eric Nieuwland wrote:

 > Ron Adam wrote:
 >
 >> Eric Nieuwland wrote:
 >>
 >>> This is linear. No looping whatsoever. And easily translated to a
 >>> simple language construct and a protocol:
 >>>
 >>> class resource(object):
 >>>     def __init__(self,...):
 >>>         # store resource parameters
 >>>     def __acquire__(self):
 >>>         # whatever it takes to grab the resource
 >>>     def __release__(self):
 >>>         # free the resource
 >>
 >>
 >>
 >>
 >> I wanted to see what the examples in PEP340 would look like written with
 >> standard class's using object inheritance and overriding to define
 >> resource managers.  If anyone's interested I can post it.
 >
 >
 > I'm interested.
 >
 >> My block class is non-looping as I found in most cases looping isn't
 >> required, and looping complicates things because you have to pass around
 >> a loop expression due to not all loops will want to behave that same 
way.
 >>
 >> The solution was to put the loop in the body method and call a
 >> repeat_body method (the repeated body section) which is added to the
 >> class when needed.
 >
 >
 > Show us your stuff! ;-)
 >
 > --eric
 >
Ok,  :)

These probably can be improved on, and renamed, and I don't know how 
many problems there may be with it, but they work in these examples. 
This is just one way to do it,  so critique, correct, and improve as 
needed.  Just no flames please.  ;-)

Cheers,  Ron_Adam


# --- start ---
## blockclass.py


##  A base class that manages resource acquire and release.
class Block(object):
    """A manager class for working with resources."""
    def __init__(self,*args):
        self._cleanup = False
        self.__err__ = None
        try:
            self.start(*args)
            self._cleanup = True
        except:
            raise
    def __call__(self, *args):
        self.block(*args)
        self.__del__()
    def __del__(self):
        if self._cleanup:
            try:
                self.final()
                self._cleanup = False
            except:
                raise
            if self.__err__:
                raise self.__err__
    def start(self,*args):
        """Override to add initialization code"""
        pass
    def final(self):
        """Override to add finalization code"""
        pass
    def block(self,*args):
        """Override to add main block body"""
        pass


## A dummy lock for test calls only
class mylock:
    def acquire(self):
        print "Lock acquired"
    def release(self):
        print "Lock released"


## 1. A template for ensuring that a lock, acquired at the start of a
##       block, is released when the block is left:
class Get_Lock(Block):
    def start(self, lock):
        self.lock = lock
        self.lock.acquire()
    def final(self):
        self.lock.release()
    def block(self):
        pass

class Lock_It(Get_Lock):
    def block(self):
        print "Do stuff while locked"
       Lock_It(mylock())()


## 2. A template for opening a file that ensures the file is closed:
class File_Opener(Block):
    def start(self, filename, mode='r'):
        self.filename = filename
        self.mode = mode
        self.f = open(filename, mode)
    def final(self):
        self.f.close()
    def block(self):
        pass

class Line_Printer(File_Opener):
    def block(self):
        n = 0
        for line in self.f:
            print n, line.rstrip()
            n += 1

Line_Printer('blockclass.py')()



### 3. A template for committing or rolling back a database:
#def transactional(db):
#    try:
#        yield
#    except:
#        db.rollback()
#        raise
#    else:
#        db.commit()

"""I'm not exactly sure how this one should work, so maybe some
one else can give an example using the block class above."""



## 4. A template that tries something up to n times:
import urllib
class Auto_Retry(Block):
    def start(self, n=3, exc=Exception):
        self.n = n
        self.exc = exc
    def block(self, *args):
        while self.n:
            try:
                self.repeat_block(*args)
                break
            except self.exc, self.__err__:
                self.n -= 1
    def repeat_block(self, *args):
        """Try this block n times"""
        pass

class Retry_Url(Auto_Retry):
    def repeat_block(self, url):
        f = urllib.urlopen(url)
        print f.read()

# This could be slow, so wait for it.
try:
    Retry_Url(3, IOError)("http://cantfind.com/this.html")
except IOError, err:
    print err

Retry_Url(3, IOError)("http://python.org/peps/pep-0340.html")



## 5. It is possible to nest blocks and combine templates:
class Lockit(Get_Lock):
    def block(self, job):
        job()

Lockit(mylock())(Line_Printer("blockclass.py"))



## 7. Redirect stdout temporarily:
import sys
class Redirect_Stdout(Block):
    def start(self, handle=sys.stdout):
        self.save_stdout = sys.stdout
        sys.stdout = handle
    def final(self):
        sys.stdout.close()
        sys.stdout = self.save_stdout
    def block(self):
        pass

class New_Out(Redirect_Stdout):
    def block(self):
        print "Writing to redirected std_out"

New_Out(open('newfile.txt','w'))()



## 8. A variant on opening() that also returns an
##    error condition:
class Append_To(File_Opener):
    def start(self, filename):
        self.f = open(filename, 'a')
    def block(self, string):
        self.f.write(string)

def append_w_error(file,sting):
    try:
        Append_To(file)(string)
    except IOError, err:
        print "IOError:", err

append_w_error("/etc/passwd", "guido::0:0::/:/bin/sh\n")

# --- end ---








More information about the Python-Dev mailing list