assert when subclassing rules are not followed

This commit is contained in:
Josh Wilson 2007-06-10 08:35:09 +00:00
parent 5e3a807168
commit 386bf49c0d

View File

@ -3,13 +3,14 @@ class ResourceCounter(object):
""" """
This class is an attempt to combine the RAIA idiom with reference This class is an attempt to combine the RAIA idiom with reference
counting semantics in order to model shared resources. RAIA stands counting semantics in order to model shared resources. RAIA stands
for "Resource Allocation Is Acquisiton" (see 'Effective C++' for a for "Resource Allocation Is Acquisition" (see 'Effective C++' for a
more detailed explanation) more in-depth explanation)
When a resource is needed, create an appropriate ResourceCounter When a resource is needed, create an appropriate ResourceCounter
object. If the resource is already available (meaning another object. If the resource is already available (meaning another
ResourceCounter object of the same type already exists), no action ResourceCounter object of the same type already exists), no action
is taken. The resource will remain valid until all matching is taken. Otherwise, acquire() is invoked, and the resource is
allocated. The resource will remain valid until all matching
ResourceCounter objects have been deleted. When no objects of ResourceCounter objects have been deleted. When no objects of
a particular ResourceCounter type exist, the release() function for a particular ResourceCounter type exist, the release() function for
that type is invoked and the managed resource is cleaned up. that type is invoked and the managed resource is cleaned up.
@ -27,10 +28,11 @@ class ResourceCounter(object):
Until we figure out a way to wrangle a bit more functionality out Until we figure out a way to wrangle a bit more functionality out
of Python, you MUST NOT define acquire() and release() again in of Python, you MUST NOT define acquire() and release() again in
any subclasses of your ResourceCounter subclass in an attempt any subclasses of your ResourceCounter subclass in an attempt
to manage another resource. If you have more than one resource, to manage another resource. In debug mode, this will raise a
runtime assertion. If you have more than one resource, you should
subclass ResourceCounter again. See the example code at the subclass ResourceCounter again. See the example code at the
bottom of this file to see how to manage more than one resource with bottom of this file to see how to manage more than one resource
a single instance of an object (Useful for dependent resources). with a single instance of an object (Useful for dependent resources).
""" """
@classmethod @classmethod
@ -46,19 +48,23 @@ class ResourceCounter(object):
@classmethod @classmethod
def decrementCounter(cls): def decrementCounter(cls):
cls.RESOURCE_COUNTER -= 1 cls.RESOURCE_COUNTER -= 1
if cls.RESOURCE_COUNTER < 1:
if cls.RESOURCE_COUNTER == 0:
cls.release() cls.release()
@classmethod @classmethod
def acquire(cls): def acquire(cls):
pass cls.RESOURCE_COUNTER -= 1
assert cls.__mro__[1] == ResourceCounter, \
(lambda: \
'acquire() should only be defined in ResourceCounter\'s immediate subclass: %s' \
% cls.__mro__[list(cls.__mro__).index(ResourceCounter) - 1].__name__)()
cls.RESOURCE_COUNTER += 1
@classmethod @classmethod
def release(cls, *args, **kwargs): def release(cls, *args, **kwargs):
pass pass
def __init__(self): def __init__(self):
self.incrementCounter() self.incrementCounter()
@ -73,19 +79,20 @@ if __debug__ and __name__ == '__main__':
""" """
@classmethod @classmethod
def acquire(cls): def acquire(cls):
ResourceCounter.acquire() super(MouseResource, cls).acquire()
print '-- Acquiring Mouse' print '-- Acquire Mouse'
@classmethod @classmethod
def release(cls): def release(cls):
ResourceCounter.release() print '-- Release Mouse'
print '-- Releasing Mouse' super(MouseResource, cls).release()
def __init__(self): def __init__(self):
ResourceCounter.__init__(self) super(MouseResource, self).__init__()
def __del__(self): def __del__(self):
ResourceCounter.__del__(self) super(MouseResource, self).__del__()
class CursorResource(ResourceCounter): class CursorResource(ResourceCounter):
""" """
@ -93,26 +100,38 @@ if __debug__ and __name__ == '__main__':
resource. Notice how this class also inherits from resource. Notice how this class also inherits from
ResourceCounter. Instead of subclassing MouseCounter, ResourceCounter. Instead of subclassing MouseCounter,
we will just acquire it in our __init__() and release we will just acquire it in our __init__() and release
it in our it in our __del__().
""" """
@classmethod @classmethod
def acquire(cls): def acquire(cls):
print '-- Acquiring Cursor' super(CursorResource, cls).acquire()
ResourceCounter.acquire() print '-- Acquire Cursor'
@classmethod @classmethod
def release(cls): def release(cls):
print '-- Releasing Cursor' print '-- Release Cursor'
ResourceCounter.release() super(CursorResource, cls).release()
def __init__(self): def __init__(self):
self.__mouseResource = MouseResource() self.__mouseResource = MouseResource()
ResourceCounter.__init__(self) super(CursorResource, self).__init__()
def __del__(self): def __del__(self):
ResourceCounter.__del__(self) super(CursorResource, self).__del__()
del self.__mouseResource del self.__mouseResource
class InvalidResource(MouseResource):
@classmethod
def acquire(cls):
super(InvalidResource, cls).acquire()
print '-- Acquire Invalid'
@classmethod
def release(cls):
print '-- Release Invalid'
super(InvalidResource, cls).release()
print '\nAllocate Mouse' print '\nAllocate Mouse'
m = MouseResource() m = MouseResource()
print 'Free up Mouse' print 'Free up Mouse'
@ -155,6 +174,13 @@ if __debug__ and __name__ == '__main__':
print 'Free up Cursor' print 'Free up Cursor'
del c del c
# example of an invalid subclass
try:
print '\nAllocate Invalid'
i = InvalidResource()
print 'Free up Invalid'
except AssertionError,e:
print e
def demoFunc(): def demoFunc():
print '\nAllocate Cursor within function' print '\nAllocate Cursor within function'
@ -162,5 +188,6 @@ if __debug__ and __name__ == '__main__':
print 'Cursor will be freed on function exit' print 'Cursor will be freed on function exit'
demoFunc() demoFunc()