Tuesday, April 12, 2011

Duck-typing in practice

As a recent Python devotee, I have found that duck-typing can sometimes be harder in practice than in theory. In theory, if it looks like a duck, swims like a duck, and quacks like a duck, then it's a duck. In practice, or at least in my practice, there are ducks incapable of flight. Or wolves in ducks' clothing. All attempted humor aside, there is difficulty in reconciling a type-based view of object oriented programming and the much more laissez-faire approach that Python adopts.

It should be obvious that duck-typing provides a more variable approach to implementation, something which was included in the driving factors behind the invention of OOP. Nonetheless, #python on freenode is inundated with questions from inexperienced programmers as to the proper way to distinguish a list from a string, or other similar situations. I will side with the operators of #python and assert that the correct way doesn't happen to be isinstance(). This function's usage is contrary to the idea of duck-typing and, in its positive form, should be avoided at all costs. However, how does one distinguish a list from a string?

On the surface, there are many similarities between these two datatypes. Both possess a length, have __add__ ,__mul__ , and  __contains__ methods. One example of a method they don't share is the append method.

What I am getting to is that, while duck-typing ensures that a function, or bit of code will work regardless of type, so long as it has the proper interface, what happens when two things share the relevant methods and the only thing distinguishing them is irrelevant to the problem at hand? It is easy to dismiss these situations as inconsequential given the nature of duck-typing (if they share the relevant interface, then it SHOULD work). But is it possible to make concessions? Is duck-typing compatible with negative definition by type (a set of "is not isinstance()" checks)? After all, if something looks like a duck, swims like a duck, and quacks like a duck, can we at least check to make sure it isn't a wolf in duck's clothing?

If the number of question marks in this post are any indication, I invite discussion on this topic, perhaps someone more knowledgeable than me will have more declarative sentences.

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.

Thursday, April 7, 2011

Post[0];

As a professionally-oriented blog, and moreover, a software oriented one, this will be terse and to the point. Personal details will be kept to a minimum, software details will be explored at a significant depth.

For my first post, I'd like to describe a rather simple, and no-doubt popular technique that I have been using recently while coding in python. This technique is what I call a 'keyword argument'. Inspired by the type of argument in python that can be passed to a function as follows:


def foo(**kwargs):
    for (key,value) in kwargs.items():
        print "%s for %s" % (key,value)
if __name__ == "__main__":
    foo(a = 1, b = 2, c = 3)
the output of this program is of course (or some permutation of the following): 
a for 1
c for 3 
b for 2
now what is interesting about this idea? It is a fairly standard way of passing variable-length arguments where values are assigned to variables. The way it has interested me is to borrow this kind of pattern, except instead of using a dictionary built by the python interpreter out of arguments to a function, I use a "command" function which builds this dictionary from some input. A simplified version is as follows (please ignore the naive regex):

def command(self, command_string):
    command_root = re.findall(r"^(\w+)",command_string)
    key_argument_tuples = re.findall(r"--([\w]+)=([^ ^=]+)",command_string)
    for x in key_args:
        cmd_dict[x[0]] = x[1]
    self.function_dict[command_root](kwargs=cmd_dict)

this is an extremely simple way (through the use of first-class functions) to build arguments for functions through a generic interface. I will clarify the part about first-class functions (self.function_dict) in my next post.


blog->previouspost = currentpost;