0

I have a map which says maps a string to a function like :

validator = {'first_name' : validate_str,
             'last_name' : validate_str,
             'phone' : validate_phone }

I need to call the corresponding validate function based on the type of value I have in the map that will be fed to me as input for e.g.

for name in elements:
    # Validate the value of this name in the input map using the function
    # input is the map that has the value for each of these fields
    # elements is a list of all fields used to loop through one input at a time
    if validator[name]( input[name] ) is False:
        # Throw validation error
    else:
        # Do something else

This works fine unless for this scenario I am not sure if it can be done:

The validate_str also checks if a given string is of desired max length.

def validate_str(str, max-len):
    # Throw error if len(str) > max-len

The max-len can differ based on the string, so I need to call validate_str for first_name with say 64 characters and last name with 256 characters.

I can use a different map to say that this field has this max_len, but is it possible for the validator map to have pointer to the validate_str function with the max-len argument preset based on the field?

something like:

validator = {'first_name' : validate_str(max-len=64),
             'last_name' : validate_str(max-len=256),
             'phone' : validate_phone }

then call it for validation like:

if validator[name]( str=input[name] ) is False:
    # The appropriate value for max-len goes with the function call and just the
    # str is appended to the argument list while invoking. 

This makes life easier so that we need not then remember again what fields will have the max-len sent along with it.

3
  • possible typos: By validate do you mean validator? What is elements? It seems to be a list of strings like first_name, last_name, or a dictionary. Commented Mar 2, 2012 at 0:26
  • Corrected the mistakes.. Thanks for pointing it out.. Commented Mar 2, 2012 at 0:29
  • No problem. You might benefit from making elements a dictionary data = {'first_name':'Bob', 'last_name':'Bobley', 'phone':1234567890} and doing for field,value in data.items(): if not validator[field](value):.... Reads much more cleanly. Commented Mar 2, 2012 at 0:35

2 Answers 2

3

You could use lambda to create a function of one argument (the string being validated) but has the length defined within in:

{'first-name':lambda x: validate-str( x, 64 ), ...
Sign up to request clarification or add additional context in comments.

2 Comments

Works like a champ.. Kudos to you :-)
This is one of the two answers the OP was looking for. For reference, this is using a lambda to curry a function.
0

There are two ways to do this.

The answer you specifically asked for is how to curry it (which Scott Hunter answered).

Another way is to use a function factory ("higher-order function") to return a function which captures the custom parameters in a closure, such as:

def makeStringValidator(maxLength=64):
    def validator(string):
        return len(string)<maxLength
    return validator

In general however, restricting yourself to this system prevents you from having "cross-cutting" validation between fields. For example, if you had fields birthday_day, birthday_month, birthday_year as separate fields, you could individually verify that say each day was either 30 or 31, but wouldn't know the month in order to determine which (also leap days in February).

I however personally use this system from time to time. You can just supplement your current system with something more complicated later, if such needs arise.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.