[PEAK] Use cases for the priority feature

P.J. Eby pje at telecommunity.com
Tue Aug 17 17:16:34 EDT 2010


At 10:09 PM 8/17/2010 +0200, Christoph Zwerschke wrote:
>The posting on how to fix typical AmbiguousMethods errors is surely 
>helpful and raised the question whether a "prioritzed" methods 
>feature as discussed here is really needed: 
>http://dirtsimple.org/2010/08/simplifying-prioritized-methods-in-peak.html
>
>So I tried to come up with some legit use cases for priorities:
>
>1) You can take the example from the docs where you get different 
>discounts based on the customer, type of product.
>
>Assume you get a discount of 10% percent if your name is Elvis, 5% 
>if you buy shoes. As usual the rule shall be that you can only get 
>the highest available account, i.e. if you're Elvis you get shoes at 
>10% discount, not 15%.
>
>With the priority feature, you could write:
>
>@when(getDiscount, "customer=='Elvis'", priority=10)
>def ElvisGetsTenPercentOff(product, customer, options):
>     return 0.1
>
>@when(getDiscount, "product is shoes", priority=5)
>def ShoesAretOnOffer(product, customer, options):
>     return 0.05
>
>2) Assume you have a generic function for resizing pictures. 
>Depending on the format, size and number of colors, different 
>algorithms are used. If the output quality of the algorithm is 
>different, you could use that quality as the priority parameter.
>
>3) Assume you have a generic "notify" method, and depending on 
>whether the user has set E-Mail, Google Wave, IRC, etc. addresses, 
>the corresponding notification method is chosen. You want to choose 
>the most sophisticated method where a notification address is 
>available, and make it configurable that e.g. Google Wave now has a 
>lower priority, maybe even reading priorities from a config file.

You haven't seen the new combine_using decorator, have you?  ;-)

from peak.rules import combine_using, when

@combine_using(max)
def getDiscount(...):
     return 0

@when(getDiscount, "customer=='Elvis'")(value(.1))
@when(getDiscount, "product is shoes")(value(.05))

When you use combine_using, all applicable methods are invoked in an 
order that's the same as if they were all "before" methods, and the 
return values are put in an iterator that's combined by whatever 
functions you put in the combine_using() call -- e.g. min, max, ' 
'.join, itertools.chain...  a customer function...  whatever you want.

All of your examples can be done this way, e.g.:

@combine_using(partial(max,key=attrgetter('quality')))
@abstract
def getResizeAlgorithm(...)
     pass

@when(getResizeAlgorithm, "some 
condition")(value(ResizingAlgorithm(somefunc, quality=20)))

Ironically, you're actually convincing me more that putting a 
priority feature in is a really bad idea, as it would encourage 
people to use it in place of deciding what kind of ranking they 
actually want to use.  ;-)

(It has occurred to me, though, that PEAK-Rules' "before" and "after" 
method orders may be screwed up, in that methods defined later should 
actually be treated as *more* specific, not less.  Unfortunately, if 
I change that now, it might break other people's code using "before" 
methods.  OTOH, I'm not sure whether anybody is actually using 
before/after methods...)



More information about the PEAK mailing list