August 31, 2005

Named Arguments, Python, and PyObjC

Filed under: ResearchAndDevelopment — Ryan Wilcox @ 9:30 am

It’s been a while since I’ve posted on here, but it’s been kinda busy these last few months.

Anyway, Today I was writing some PyObjC, I found an interesting issue: NSObject based classes don’t handle functions called with keyword arguments.

Click the More Link below to read more…

“Normal” Python has a construct that allows you to pass a variable number of “labeled” parameters to a function.

Examining The Python “Named Arguments” Syntax

Named arguments are useful in Python, like many languages, sometimes to just make the code easier to read. Sometimes named parameters allow useful tricks to be played with the language.

Take the following code, which takes one required argument, and an arbitrary number of additional named arguments. We simply print the required parameter, then iterate through the additional named arguments, printing their argument name and value.


#!/usr/bin/env python

def myKeywordedFunction(requiredParameter, **otherParams):
print "requiredParameter was", requiredParameter
print "now to tackle the passed parameters..."

for each in otherParams.iteritems():
print "key =", each[0], ", value =", each[1]

myKeywordedFunction("hello world", mine=42, powerbook="excalibur")

A quick pass through the constructs to keep everybody on the same page:

  • the **otherParams construction means that any named arguments that aren’t explicitly in the argument list of the function should be put into a dictionary named “otherParams”.

    Note that we could have called myKeywordedFunction() like so:

    myKeywordedFunction(requiredParameter="hello world", mine=42, powerbook="excalibur")

  • otherParams.iteritems() loops through a Python dictionary returning a key/value pair for every item.

    We also could have used the
    iterkeys() function, putting only the “current” key into each. (or for each in dictionaryVariable, which is the same thing).

    To simply iterate through the values, we could have used itervalues()… but that’s not what we wanted.

  • There’s also a “unnamed argument” syntax, which goes like:

    def myArbitraryArgumentsFunction(required, *otherParams):

    To call this code one would:

    myArbitraryArgumentsFunction("hello world", 1, 2, 3, 4, 5, 42, excalibur)

    *otherParams is now a list of the “extra” parameters provided to the function

Named Arguments and PyObjC

A NSObject-based PyObjC class follows:


class MyAppDelegate(NibClassBuilder.AutoBaseClass):
def init():
self.mModel = [] #will be a list of dictionaries.
return self

def awakeFromNib(self):
self.addToModel(hello="world")

def addToModel(self, **nam_args):
print nam_args
self.mModel.append(nam_args)

If you create a PyObjC project with this code and run it, you should see that nam_args is empty!!

My suggested workaround is: don’t do that. For this example, and for my own program, it’s easy enough to construct the dictionary by hand:

self.addToModel({'hello': 'world'})

Conclusion

I can make a hypothesis as to why this happens (I suspect python objc method conversion may have something to do with this). I’m not even sure if this is a bug or an “unintended design consequence”. I just know that it’s annoying and I spent about 15 minutes trying to figure out why my code wasn’t working. Hope to save someone else the hassle.

Have a comment? You should be able to comment using the Movable Type Comment Feature. If that’s turned off, or doesn’t work, feel free to use my Web Contact Form and I’ll insert your comments into this story myself.

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.