Iterate through a list calling functions

D

David Pratt

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 ...
 
K

Kent Johnson

David said:
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

Actually you can do exactly that by putting references to the validator functions in your list instead of (string) name. For example if you have
validators = [ 'isDecimal', 'isFoo', 'isBar' ]

just change it to
validators = [ isDecimal, isFoo, isBar ]

and your loop above will work.

Python makes data-driven programming easy :)
Kent
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 ...
 
G

George Sakkis

David said:
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
 
K

Kent Johnson

George said:
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.'''

Why is this better than an isDecimal function?

def isDecimal(name, value):
''' Test whether numeric value is a decimal.'''

seems simpler and more straightforward to me.
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

No change needed in the loop above...
# test
validators = [DecimalValidator(), ZipCodeValidator()]
validators = [ isDecimal, isZipCode ]

Kent
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,147
Latest member
CarenSchni
Top