Friday, April 8, 2011

Keywordargs Followup

This is a follow-up post to my very first blog post, in which I introduced a pattern that I like to use. In this post I will clarify a bit of the reasoning behind me using it, and perhaps why you should use it as well.

So that's all well and good but what's the benefit of using this pattern? Having a variable number of arguments can be extremely useful, and often can allow one to achieve desired behavior with less effort. However, it can at times increase the ambiguity of a function, or decrease its security. Having arguments assigned to keywords definitely reduces ambiguity, although it can increase the number of keystrokes for doing even a simple task. With this in mind, some of the benefits of using this method are:

  • Variable composition of arguments without using something like overloading, which should reduce code duplication. An example of this is: say you wanted to create a function that plots some form of graph. You want to have one function to handle both 2d and 3d graphing, with the data to be graphed passed as arguments. One way of checking which case you're in is to do something like set(['axis1','axis2','axis3']).issubset(kwargs.keys()). This is one of those moments where I really appreciate python's clarity and respect for mathematics.
  • Regex-based searching of arguments can be extremely useful, especially when these keyword-argument dicts are being formed from user input. 
  • Since the arguments are stored as a dict, one can have several dictionaries with sets of default values for this functions behavior. If, like in the previous example, you discovered the user was trying to plot 3d data, it would be easy to provide a set of default values for that particular circumstance
In order to really properly leverage the power of having dictionaries holding the default values, I think it requires an additional behavior to the dict type:

class updict(dict):
        def healthyMerge(self, target):
                if not target.keys():
                        return 
                for (key,value) in target.iteritems():
                    self.update(tup for tup in target.iteritems() if tup[0] not in self)


if __name__=="__main__":
        testDict = updict()
        mergeDict = {}

        testDict['a']=1
        testDict['b']=2

        mergeDict['b']=None
        mergeDict['c'] = 3

        testDict.healthyMerge(mergeDict)
        print testDict

        testDict.update(mergeDict)
        print testDict
(Thanks to the redditor wot-the-phuck for a very pythonic suggestion for my code
discussion located at:
http://www.reddit.com/r/Python/comments/gloje/usage_of_dictionary_arguments_in_python/c1oglxf)

Here you'll see something I've named healthyMerge because I'm not exactly sure what the proper name of this kind of merge is. Since it seems that the basic dict class lacks a way of simply updating a dictionary with values that aren't already set, I've created a very simple one. I make no guarantees about this code, it just serves as an example.

No comments:

Post a Comment