Batman
Batman

Reputation: 8947

Dictionary-like class that defaults to a function that does nothing

I want to parse data from a file, and for each line I want to validate each piece of data. Imagine that the first few lines of the file look something like this:

id|date|rate|notes
1|2016-07-23|0.765|foo
2|2016-07-23|0.432| 
1|2016-07-24|0.697|bar

I want to make sure that the date and rate values are valid, and I have functions that can check that they are. These functions return a value if the input is valid, and throw an error if it's not. E.g:

def validate_date(string):
    parts = [int(x) for x in string.split("-")
    return datetime.date(*parts)

I don't care about the values of the id or notes fields. So I can do this:

validators = dict()
validators['id'] = lambda x: x 
validators['date'] = validate_date
validators['rate'] = validate_rate
validators['notes'] = lambda x: x

Then, once I've read in each row (as a dictionary) I can validate each field like so:

output = dict()
for key, value in line.iteritems()
    output[key] = validators[key](value)
return output

Which is all great. The problem is that the file I want to parse actually has dozens of fields that I don't care about, and only a handful that I do. So, instead of manually having to define a line like validators['id'] = lambda x: x, what I'd like to do is use something like a defaultdict to return a function that simply returns the input. But, if I try:

def do_nothing(x):
    return x

foo = defaultdict(do_nothing)
foo['bar'](1)

I get the error: do_nothing() takes exactly 1 argument (0 given).

Is there a way to create something that is like a defaultdict, but that returns an object that can take an argument?

Upvotes: 0

Views: 78

Answers (1)

tdelaney
tdelaney

Reputation: 77367

The defaultdict returns whatever was created by its default function so all you need is for do_nothing to return a callable that takes one param. You don't really need do_nothing at all, just

 validators = collections.defaultdict(lambda: lambda x: x)

Now defaultdict returns lambda x: x which takes one parameter so you can do

validators['foo'](1)

and the lambda is called with 1.

Upvotes: 3

Related Questions