For those not familiar with the way pattern matching works, I've copied the example from the article above.
%% handle(Path, Method)What the above code does is to return "not a resource" if you call the handle function with the path parameter as "/" and any method. If you call handle with any path and method parameter as "GET" then it calls retrieve_resource(Path) and so on.
handle("/", _) ->
not_a_resource;
handle(Path, 'PUT') ->
create_new_resource(Path);
handle(Path, 'POST') ->
update_resource(Path);
handle(Path, 'GET') ->
retrieve_resource(Path);
handle(_, _) ->
invalid_request.
PEAK-Rules
A method to replicate this in Python was given using match objects, but I thought hey why go through all this trouble when PEAK-Rules does most of this for us?
Multimethod Dispatch
PEAK-Rules is a library that enables multimethod dispatch in Python. Those with an OO background will recognise a specific instance of this in method overloading. When an overloaded method is called, execution can go to different method implementations depending upon the type of the parameters passed. In generic multimethod dispatch, you can route execution based on any criteria that you define. PEAK-Rules brings this sort of generic multimethod dispatch to Python.
An Example
So lets take a concrete example. Our goal is to rewrite the above Erlang code in Python using two libraries: PEAK-Rules and an add-on called prioritized_methods that allows prioritised method ordering.
First, you'll need to get install PEAK-Rules and prioritized_methods. You can pick them up from the links given or if you've got setuptools, then you can just easy_install them.
Then type out the following code:
>>> from peak.rules import abstract, whenHere is what is happening:
>>> from prioritized_methods import prioritized_when
>>> @abstract()
... def handle(path, method):
... pass
...
>>> @prioritized_when(handle, "path == '/'", prio=1)
... def not_a_resource(path, method):
... print "not a resource"
...
>>> @when(handle, "method == 'GET'")
... def get_resource(path, method):
... print "getting", path
...
>>> @when(handle, "method == 'PUT'")
... def create_resource(path, method):
... print "creating", path
...
>>> @when(handle, "method == 'POST'")
... def update_resource(path, method):
... print "updating", path
...
We first define an abstract function handle(path, method). Do this by placing the @abstract() decorator on it.
Now consider this snippet:
>>> @when(handle, "method == 'GET'")This defines one implementation for the handle function. It says, when the handle function is called, and the condition given is True (in this case method == "GET"), then call the implementation given below (here: the get_resource function).
... def get_resource(path, method):
... print "getting", path
...
Similarly we define the other implementations to be called on some other conditions.
The only thing left is the usage of @prioritized_when. Now, when a call is made to handle("/", "GET"), we see that the condition for not_a_resource as well as get_resource are satisfied. Which implementation should be called? In this case, we use the @prioritized_when decorator and set the priority to 1. This tells the system to give priority to this implementation in case of conflict in match.
Here is how the output looks:
>>> handle("/", "GET")Pretty cool! The best part of this is that you can dispatch on virtually any condition. While the resulting code is a little more verbose than the Erlang example, its not too bad and it does the job well.
not a resource
>>> handle("/", "POST")
not a resource
>>> handle("/home", "PUT")
creating /home
>>> handle("/home", "POST")
updating /home
>>> handle("/home", "GET")
getting /home
1 comment:
hai admin this is very nice information for me..i didnt read this before...now i got some idea about this...thanks for sharing...please visit my blog in that i too have some useful informations..:/p
Post a Comment