Friday, March 30, 2007

Python: Class objects as signal arguments

Today I was writing python wrappers for the Windows device installation and management APIs (setupapi.dll) and ran across the SetupDiSetClassInstallParams(W) function in which I needed to not only accept a hardware profile identifier, but also accept special signal values indicating "all profiles" or "current profile". The underlying Windows API does this using a flag to specify that all profiles are to be affected, and the profile ID #0 to mean the "current profile" should be affected. However, since I'm presenting a pythonic interface with my wrappers, this was unacceptable -- I wanted named values that could be passed as the hardware profile identifier argument that would represent these two special cases.

In other words, I just needed a way to identify whether the argument passed to my wrapper was one of two reserved values I was using to signal special behavior as opposed to the actual hardware profile ID. In addition, it would be great if I could attach python doc-strings to the signal values to document what they mean and what they are used for.

I'm sure my solution is less clever than most, but I used classes as the signal values. Since classes are objects in python, I don't need to actually instantiate them -- I just use the class objects themselves as the signals. As an example:

class AllWidgets(object):
"""Placeholder for indicating action applies for all widgets

class CurrentWidget(object):
"""Placeholder for indicating action is applied for just
the currently selected widget

def ApplyFlavor(flavor, widget=CurrentWidget):
if widget is CurrentWidget:
# Code that flavors the "current widget".
elif widget is AllWidgets:
# Code that flavors all widgets.
# Code that flavors just the widget specified.

1 comment:

Shannon -jj Behrens said...

Yep :)

This happens to me sometimes when I have a function that takes a value that might be None or might be a string. I want to provide a default that means N/A, but None is a valid value. Hence, I need a "special" None. I do the same thing--I create a class called ArgNotApplicable or something like that.