Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Feb 23rd, 2006, 6:31 PM   #1
Sane
Banned
 
Sane's Avatar
 
Join Date: Apr 2005
Location: Waterloo, Ontario
Posts: 2,101
Rep Power: 6 Sane will become famous soon enough
Send a message via MSN to Sane
<3 Decorators

After noting the power of Arevos' cache function, I wanted to see how decorators worked.

I <3 Decorators, very handy for applying a common transformation easily to your functions. It's a useful thing to learn, and very easy to understand once you see its logic.


Here's one I made for my website

def serveError(func_name, func_code, func_error):
    return """<html>
<font face="courier new">
Server has encountered an error.<br />
<br />
      Error <i>%s</i><br />
In Function <b><i>%s</i></b><br />
         At <i>%s</i><br />
<br />
</font>
</html>"""%(func_error, func_name, func_code)



from sys import exc_info
def debug_wrapper(func):
    """If an error happens inside the function
    it will be caught and appropriately acted upon."""
    def new_func(*args):
        try:
            return func(*args)
        except:
            return serveError(func.func_name, func.func_code, exc_info()[0])
    return new_func




@debug_wrapper
def foo():
    raise KeyError


print foo()


Any function I put "@debug_wrapper" before, will now display something other then a CherryPy error.

Handy. Got any interesting ones?

Edit:

Here's Arevos' cache function:

def cached(func):
    """Creates a cached function.
    Cached function cannot handle keyword or mutable arguments."""
    store = {}
    def cached_func(*args):
        if not store.has_key(args):
            store[args] = func(*args)
        return store[args]
    return cached_func

@cached
def foo(x):
    return len(x)

print foo("Hello World!") # calculates and prints 12
print foo("Hello World!") # prints 12 without calculating
Sane is offline   Reply With Quote
Old Feb 23rd, 2006, 6:35 PM   #2
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 648
Rep Power: 4 Jessehk is on a distinguished road
what does <3 mean? :p
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Old Feb 23rd, 2006, 6:42 PM   #3
OpenLoop
Expert Programmer
 
OpenLoop's Avatar
 
Join Date: May 2005
Location: East Lansing, MI
Posts: 663
Rep Power: 4 OpenLoop is on a distinguished road
<3 = Love, notice the heart shape. That's one interpretation.
OpenLoop is offline   Reply With Quote
Old Feb 23rd, 2006, 6:57 PM   #4
The Dark
Expert Programmer
 
Join Date: Jun 2005
Posts: 894
Rep Power: 4 The Dark is on a distinguished road
<3 = dropped my double scoop icecream cone
The Dark is offline   Reply With Quote
Old Feb 23rd, 2006, 6:59 PM   #5
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Multimethods spring to mind as one good use for decorators, and since a while ago we were talking about thread, here's a decorator that mimics the synchronized keyword in Java. I also find decorators quite useful for event based programming:
event_registry = {}

def listen_for(event_class):
    if event_registry.has_key(event_class):
        event_registry[event_class].append(func)
    else:
        event_registry[event_class] = [func]

    def decorator(func):
        def decorated(event):
            return func(event)
        return decorated
    return decorator

def send_event(event):
    if event_registry.has_key(event.__class__):
        for func in event_registry[event.__class__]:
            func(event)

class PokeEvent: pass

@listen_for(PokeEvent)
def poked(event):
    print "Ouch!"

send_event(PokeEvent())
Although I'd probably opt for an off-the-shelf dispatch system, rather than trying to reinvent the wheel, if I were programming a real application.
Arevos is offline   Reply With Quote
Old Feb 23rd, 2006, 8:01 PM   #6
Sane
Banned
 
Sane's Avatar
 
Join Date: Apr 2005
Location: Waterloo, Ontario
Posts: 2,101
Rep Power: 6 Sane will become famous soon enough
Send a message via MSN to Sane
Wow, that's seriously confusing... >.>
Sane is offline   Reply With Quote
Old Feb 24th, 2006, 6:51 AM   #7
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
It may look it, but the principle is really rather simple - honest!

Event based programming works by getting functions to "listen out" for events. It's common technique in GUIs and computer games. For example, if I clicked a button, a "ButtonClick" event might be sent out:
class Button:
    def click(self):
        send_event( ButtonClick(self) )
And I could have a number of functions listening for this ButtonClick:
@listen_for(ButtonClick):
def button_clicked(event):
    print "The button you pressed was called: " + event.button_name
The code itself is also simpler than it looks. All the listen_for decorator does, is to map an event class to one or more functions:
event_registry = { ButtonClick : [button_clicked] }
This tells the send_event function that when a ButtonClick event is sent, it should call the button_clicked function.
Arevos is offline   Reply With Quote
Old Feb 24th, 2006, 12:16 PM   #8
Dietrich
Professional Programmer
 
Dietrich's Avatar
 
Join Date: Feb 2005
Posts: 434
Rep Power: 4 Dietrich is on a distinguished road
Arevos,
could you please send a working example?
__________________
I looked it up on the Intergnats!
Dietrich is offline   Reply With Quote
Old Feb 24th, 2006, 1:11 PM   #9
Cerulean
Professional Programmer
 
Cerulean's Avatar
 
Join Date: Apr 2005
Location: London, England
Posts: 459
Rep Power: 4 Cerulean is on a distinguished road
That's pretty cool. I'm fonder of the maintenance free signal/slot implementation, however. Python cookbook at its best!
Cerulean is offline   Reply With Quote
Old Feb 24th, 2006, 3:16 PM   #10
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
I prefer the dispatch method myself. It seems to me to be a more abstracted model, cleanly separating the concept of event handling and the events themselves.

As for a working example, I'll provide a simple one for demonstration purposes, though I'd advise using a library like pydispatcher instead.

event_registry = {}

def connect(event_class, function):
	"""Maps an event class to a function. Multiple functions can be mapped
	to the same event class."""
	try:
		event_registry[event_class].append(function)
	except KeyError:
		event_registry[event_class] = [function]

def listen_for(event_class):
	"""Decorator for the 'connect' function"""
	def decorator(function):
		connect(event_class, function)
		return function
	return decorator

def send_event(event):
	"""Send an event to all functions that are listening for events of
	that type."""
	try:
		functions = event_registry[event.__class__]
	except KeyError:
		return
	
	for function in functions:
		function(event)
		
		
def main():
	"""Demonstration of how these events are used."""	
	class PokeEvent:
		"""A generic event"""
		def __init__(self, name):
			self.name = name
	
	@listen_for(PokeEvent)
	def poked(event):
		"""A function to be activated by an event"""
		print "Ouch! I was poked by %s" % event.name
	
	# Send a new PokeEvent. Should be caught by the "poked" function
	send_event(PokeEvent("Fred"))

if __name__ == '__main__':
	main()
This is similar to the code I posted before, but better laid out, commented, and without the errors
Arevos is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 12:43 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC