Decorator for validation - inefficient?
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Fri Oct 31 21:04:13 EDT 2008
On Fri, 31 Oct 2008 11:26:19 -0700, Bryan wrote:
> I want my business objects to be able to do this:
[snip code]
The code you show is quite long and complex and frankly I don't have the
time to study it in detail at the moment, but I can make a couple of
quick comments. I see by your subject line that you're (probably)
complaining about it being inefficient.
I notice that in the validation code, you do this:
> def _get_invalid(self):
> """Collect all validation results from registered validators"""
> result = []
> for attrName in dir(self):
> # Prevent recursive calls
> if attrName == 'get_invalid' or attrName == 'invalid':
> continue
> attr = eval('self.' + attrName) # Get attribute
That's slow and wasteful. The right way to get an attribute is with
getattr:
attr = getattr(self, attname)
I haven't tested this specifically, but in the past my timing tests
suggest that x.attr or getattr() will run about ten times faster than
eval('x.attr').
> if str(type(attr)) == "<type 'instancemethod'>":
This is probably also slow and wasteful. Why convert the instance into a
string and then do a string comparison?
At the top level of your module, do this once:
import new
and then in the validation method do this:
if type(attr) is new.instancemethod:
or better still:
if isinstance(attr, new.instancemethod):
> valerr = attr() # Get result of validation
> # Validation result can be a single string, list
> # of strings, or None.
> # If the validation fails, it will be a string or
> # list of strings
> # which describe what the validation errors are.
> # If the validation succeeds, None is returned.
> if type(valerr) == type([]):
> for err in valerr:
> result.append(err)
> else:
> if valerr != None: result.append(valerr)
This whole approach is unpythonic. That doesn't mean it's wrong, but it
does suggest you should rethink it. I recommend that the validation test
should simply raise an exception if the validation fails, and let the
calling code deal with it.
Hope this helps, and I may have another look at your code later today.
--
Steven
More information about the Python-list
mailing list