Iterate through a list calling functions

George Sakkis gsakkis at rutgers.edu
Sun Jun 5 19:49:53 CEST 2005


David Pratt wrote:
> Hi.  I am creating methods for form validation. Each validator has its
> own method and there quite a number of these.  For each field, I want
> to evaluate errors using one or more  validators so I want to execute
> the appropriate validator methods from those available.  I am iterating
> over each validator using validateField method to gather my results. It
> works but it ugly and inefficient.  Can someone advise whether there is
> a better way of doing this.  I realize that the validator variable in
> my iteration is only a string so question is how can I make the
> validator string reference a function so I may be able to shorten
> validateField to something similar to this (instead of my long list of
> ifs which I am not very happy with):
>
> 	for validator in validators_list:
> 		result = validator(name, value)
> 		if type (result) in StringTypes:
> 		results[name] = result
>
> Many thanks
> David
>
> My current situation below:
>
> # A large list of validators
> def isDecimal(name, value):
> 	""" Test whether numeric value is a decimal """
> 	result = validateRegex(name,
> 		value,
> 		r'^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$',
> 		errmsg='is not a decimal number.',
> 		ignore=None)
> 	return result
>
> def isZipCode(name, value):
> 	""" Tests if field value is a US Zip Code """
> 	result = validateRegex(name,
> 		value,
> 		r'^(\d{5}|\d{9})$',
> 		errmsg='is not a valid zip code.',
> 		ignore=None)
> 	return result
>
> ... more validators
>
> # Iterating over validators to gather field errors
> def validateField(name, value, validators_list, range=None,
> valid_values=None):
> 	""" Validates field input """
> 	results={}
> 	for validator in validators_list:
> 		if validator == 'isContainedIn':
> 			result = isContainedIn(name, value)
> 			if type (result) in StringTypes:
> 				more...
> 		if validator == 'isDate':
> 			result = isDate(name, value)
> 			if type (result) in StringTypes:
> 				more...
> 		if validator == 'isDecimal':
> 			result = isDecimal(name, value)
> 			if type (result) in StringTypes:
> 				more...
>
>                   more validators ...


That's a typical case for using an OO approach; just make a class for
each validator and have a single polymorphic validate method (I would
make validators __call__able instead of naming the method 'validate'):

# Abstract Validator class; not strictly necessary but good for
documentation
class Validator(object):
    def __call__(self,field,value):
        '''Validate a value for this field.
        Return a string representation of value on success, or None on
failure.
        '''
        raise NotImplementedError("Abstract method")


class DecimalValidator(Validator):
    def __call__(self,name,value):
        '''Test whether numeric value is a decimal.'''

class ZipCodeValidator(Validator):
    def __call__(self,name,value):
        '''Test if value is a US Zip Code.'''


def validateField(name, value, validators):
    """ Validates field input """
    results = {}
    for validate in validators:
        result = validate(name,value)
        if result is not None:
            results[name] = result
            # XXX: if more than one validators succeed,
            # all but the last result will be overwritten
    return results

# test
validators = [DecimalValidator(), ZipCodeValidator()]
print validateField("home ZIP", "94303", validators)

Regards,
George




More information about the Python-list mailing list