In Python, a Decorator is a type of macro that allows you to inject or modify code in functions or classes. I was turned onto this by my friend Matt Chapman at ILM, but never fully grasped the importance.
class myDecorator(object):
def __init__(self, f):
self.f = f
def __call__(self):
print "Entering", self.f.__name__
self.f()
print "Exited", self.f.__name__
@myDecorator
def aFunction():
print "aFunction running"
aFunction() |
class myDecorator(object):
def __init__(self, f):
self.f = f
def __call__(self):
print "Entering", self.f.__name__
self.f()
print "Exited", self.f.__name__
@myDecorator
def aFunction():
print "aFunction running"
aFunction()
When you run the code above you will see the following:
>>Entering aFunction
>>aFunction running
>>Exited aFunction |
>>Entering aFunction
>>aFunction running
>>Exited aFunction
So when we call a decorated function, we get a completely different behavior. You can wrap any existing functions, here is an example of wrapping functions for error reporting:
class catchAll:
def __init__(self, function):
self.function = function
def __call__(self, *args):
try:
return self.function(*args)
except Exception, e:
print "Error: %s" % (e)
@catchAll
def unsafe(x):
return 1 / x
print "unsafe(1): ", unsafe(1)
print "unsafe(0): ", unsafe(0) |
class catchAll:
def __init__(self, function):
self.function = function
def __call__(self, *args):
try:
return self.function(*args)
except Exception, e:
print "Error: %s" % (e)
@catchAll
def unsafe(x):
return 1 / x
print "unsafe(1): ", unsafe(1)
print "unsafe(0): ", unsafe(0)
So when we run this and divide by zero we get:
unsafe(1): 1
unsafe(0): Error: integer division or modulo by zero |
unsafe(1): 1
unsafe(0): Error: integer division or modulo by zero
Using decorators you can make sweeping changes to existing code with minimal effort, like the error reporting function above, you could go back and just sprinkle these in older code.
posted by admin at 9:06 AM
I have really been trying to learn some Python fundamentals lately, reading some books and taking an online class. So: wow. I can’t believe that I have written so many tools, some used by really competent people at large companies, without really understanding polymorphism and other basic Python concepts.
Here’s an example of my sequence method from before, but making it a class using special class methods:
http://docs.python.org/reference/datamodel.html#specialnames
class imSequence:
def __init__(self, file):
dir = os.path.dirname(file)
file = os.path.basename(file)
segNum = re.findall(r'\d+', file)[-1]
self.numPad = len(segNum)
self.baseName = file.split(segNum)[0]
self.fileType = file.split('.')[-1]
globString = self.baseName
for i in range(0,self.numPad): globString += '?'
self.images = glob.glob(dir+'\\'+globString+file.split(segNum)[1])
def __len__(self):
return len(self.images)
def __iter__(self):
return iter(self.images) |
class imSequence:
def __init__(self, file):
dir = os.path.dirname(file)
file = os.path.basename(file)
segNum = re.findall(r'\d+', file)[-1]
self.numPad = len(segNum)
self.baseName = file.split(segNum)[0]
self.fileType = file.split('.')[-1]
globString = self.baseName
for i in range(0,self.numPad): globString += '?'
self.images = glob.glob(dir+'\\'+globString+file.split(segNum)[1])
def __len__(self):
return len(self.images)
def __iter__(self):
return iter(self.images)
Here’s an example of use:
seq = imSequence('seq\\test_00087.tga')
print len(seq)
>>94
print 'BaseName: %s FileType: %s Padding: %s' % (seq.baseName, seq.fileType, seq.numPad)
>>BaseName: test_ FileType: tga Padding: 5
for image in seq: print image
>>seq\test_00000.tga
>>seq\test_00001.tga
>>seq\test_000002.tga
... |
seq = imSequence('seq\\test_00087.tga')
print len(seq)
>>94
print 'BaseName: %s FileType: %s Padding: %s' % (seq.baseName, seq.fileType, seq.numPad)
>>BaseName: test_ FileType: tga Padding: 5
for image in seq: print image
>>seq\test_00000.tga
>>seq\test_00001.tga
>>seq\test_000002.tga
...
[More info and examples: Dive Into Python: Special Class Methods]
posted by admin at 10:16 PM