Well, first thing I see, you want to be adding the param to the function object in the decorator, not the closure; the closure gets called when the function is called from the decorated scope, so tagging it within the closure is doing it after the fact:
def constraint(func):
func._is_constraint = True
@wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
Also, if all you are doing is directly calling func within the closure without adding any functionality, just tagging it, the closure is completely superfluous:
def constraint(func):
func._is_constraint = True
return func
In which case, you may be served better by a different pattern all together:
class ConstraintsType(type):
def __new__(cls, name, bases, attrs):
attrs['constraint_names'] = []
for attr in attrs:
if attr.startswith('constraint_'):
attrs['constraint_names'].append(attr)
return super(ConstraintsType, cls).__new__(cls, name, bases, attrs)
class Constraints(object):
__metaclass__ = ConstraintsType
@property
def constraints(self):
for name in self.constraint_names:
yield getattr(self, name)
class Record(Constraints):
def __init__(self, params=(100, 20)):
self.params = params
def constraint_greater_than_0(self, value):
return value > 0
def run(self):
for index, value in enumerate(self.params):
for func in self.constraints:
if not func(value):
print 'param %d (%s) did not satisfy constraint %s' % (index, value, func.__name__)
Record().run()
for value_set in ((-100, -100), (0, 0), (-1,1), (1,-1)):
Record(value_set).run()