views:

57

answers:

1

My brain feels slow today.

I'm writing pre/post/invariants in Python using decorators. Currently, I need each call to specify the locals and globals for context, and this feels ugly. Is there a way to get the locals and globals from the decorator application level even though it's an arbitrary depth.

That is, I'm trying to make this ugly code: from dectools import invariant, pre, post, call_if

@invariant("self.price >= 0 and self.inventory >= 0 and Item.tax_rate >= 0")
class Item(object):
    tax_rate = 0.10  # California.  No property taxes on old property.

    @post("ItemDB.fetch(self) = (name, price)", locals(), globals())
    def __init__(self, name, price):
        self.name = name
        self.price = price
        self.total_sold = 0
        self.inventory = 0

    @call_if(check_level, "manager")
    @post("self.total_sold > 0", locals(), globals())
    @pre("discount > 0 and discount <= self.price * 0.50", locals(), globals())
    def adjust_price(self, adjustment):
         ....

into the same ugly code without all the "locals(), globals()". I run into problems where the nested decorators give me arbitrary stack depths, so my implementation of dectools.pre couldn't grab from a constant depth sys._getframe(). The stack is not something I've played with much, and would appreciate it if someone has a trick. (Yes, I'm hacking the local variables into the locals by assuming self will be in the right stack frame. It's the Item.tax_rate that is always out of scope, and self, and ItemDB.)

Thank you in advance,

Charles

+2  A: 

If you can access self.total_sold, you can access self.tax_rate (which is the same thing as Item.tax_rate unless you stomp on it -- so you just don't stomp of it, keep the tax rate as a pristine class variable, and access it through self.!-). That would be much more solid than mucking through the stack, especially with nested decorators in the picture, which more or less guarantees fragile, specific-version-dependent code (stack introspection is meant to be used for debugging purposes, essentially, not for production purposes).

Alex Martelli