print convert_to_customer_format(data, default_item)
customer_interface.send(convert_to_customer_format(data, default_item))
the print line had been innocently added for debug, but it caused an error in the customer interface component, as the line had been added to assist with debug on the customer interface component it was a while before the error was traced back to the code above. We log all calls and returns from functions, so it didn't take long to realise that what we were printing was different to what we were trying to send, so suspicion quickly fell on the conversion function:
def convert_to_customer_format(data, default_item):
#turn into list
for key in data.keys():
data[key].insert(0, key)
data = data.values()
#pad with empty items
default_item.insert(0, 'Empty')
number_of_pads = range(len(data), 16)
for x in number_of_pads:
data.append(default_item)
return data
It's not a very pretty function, but you if you run it like so:
default_item = [0, 0, 0, 0]
data = defaultdict(lambda:default_item)
data['foo'] = [1, 2, 3, 4]
data['bar'] = [5, 6, 7, 8]
x = side_effect(data, default_item)
print x
y = side_effect(data, default_item)
print y
You'll see that it changes the data each time. You wouldn't have this kind of trouble in Haskell! It got me thinking though, could I make a decorator that would force a function to not have side effects, or at least raise an exception if it did. I think I've done it, i'd appreciate comments:
def no_side_effects(func):
def inner_func(*args, **kwargs):
pre_call_args = copy.deepcopy(args)
pre_call_kwargs = copy.deepcopy(kwargs)
print 'pre_call: %s| %s' % (pre_call_args, pre_call_kwargs)
result = func(*args, **kwargs)
print 'post call: %s| %s' % (args, kwargs)
if args == pre_call_args and kwargs == pre_call_kwargs:
return result
else:
raise Exception('Side effect found: Function altered the arguments')
return inner_func
No comments:
Post a Comment