tags:

views:

74

answers:

2

I'm working with an open-source library and they define a class like so:

class Provider(object):
    """ Defines for each of the supported providers """
    DUMMY = 0
    EC2 = 1
    EC2_EU = 2
    RACKSPACE = 3
    SLICEHOST = 4
    GOGRID = 5
    VPSNET = 6
    LINODE = 7
    VCLOUD = 8
    RIMUHOSTING = 9

I need to take the properties (DUMMY, EC2, etc.) and convert them to a sorted list of tuples that would look something like this:

[(0, 'DUMMY'), (1, 'EC2'), ...]

I want to sort on the name of the property itself. I've come up with a few ways to tackle this, including the following which seems like an inefficient way to handle this:

import operator
from libcloud.types import Provider

PROVIDER_CHOICES = [(v,k) for k, v in vars(Provider).items()
                                   if not k.startswith('__')]
PROVIDER_CHOICES = sorted(PROVIDER_CHOICES, key=operator.itemgetter(1))

It works but seems inelegant and like there may be a better way. I also see flaws in the way I'm constructing the list by doing the if not k.startswith('__') - mainly what if the open-source lib adds methods to the Provider class?

Just looking for some opinions and other techniques that may work better for this.

+6  A: 

If you are looking for class variables that are of the type integer, you could do it like this:

import inspect
PROVIDER_CHOICES = inspect.getmembers(Foo, lambda x: isinstance(x, int))

Check out the inspect module for more information.


As an aside: you can use PROVIDER_CHOICES.sort(key=...) in your last line, which does an inplace sort.

Edit: getmembers returns a sorted list as stated in the documentation so sorted is unnecessary (thanks J.F. Sebastian)

Otto Allmendinger
`inspect.getmembers()` already returns list sorted by name.
J.F. Sebastian
this is great. much more elegant and easier to understand. J.F. is right I removed the `sorted()` wrapped around `inspect.getmembers()` and it sorted perfectly.
richleland
A: 

If you worry about methods and other types of attributes just filter them out too.

PROVIDER_CHOICES = [(v,k) for k, v in vars(Provider).iteritems()
                          if not k.startswith('_') and isinstance(v,int)]
PROVIDER_CHOICES.sort( key=itemgetter(1) )

You just have to run this once for every class in question, so speed shouldn't be a issue to begin with. If you really care, you can just store the list on the class itself.

THC4k