# Iterating Over Registries

Sometimes, you want to iterate over all of the classes registered in a `ClassRegistry`. There are three methods included to help you do this:

- `items()` iterates over the registry keys and corresponding classes as tuples.

- `keys()` iterates over the registry keys.

- `values()` iterates over the registered classes.

Note

Regardless of which version of Python you are using, all three of these methods return generators.

Here’s an example:

    from class_registry import ClassRegistry

    pokedex = ClassRegistry('element')

    @pokedex.register
    class Geodude(object):
      element = 'rock'

    @pokedex.register
    class Machop(object):
      element = 'fighting'

    @pokedex.register
    class Bellsprout(object):
      element = 'grass'

    assert list(pokedex.items()) == \
      [('rock', Geodude), ('fighting', Machop), ('grass', Bellsprout)]

    assert list(pokedex.keys()) == ['rock', 'fighting', 'grass']

    assert list(pokedex.values()) == [Geodude, Machop, Bellsprout]

Tip

Tired of having to add the `register()` decorator to every class?

You can use the `AutoRegister()` metaclass to automatically register all non-abstract subclasses of a particular base class. See Advanced Topics for more information.

## Changing the Sort Order

As you probably noticed, these functions iterate over classes in the order that they are registered.

If you’d like to customize this ordering, use `SortedClassRegistry`:

    from class_registry import SortedClassRegistry

    pokedex =\
      SortedClassRegistry(attr_name='element', sort_key='weight')

    @pokedex.register
    class Geodude(object):
      element = 'rock'
      weight = 1000

    @pokedex.register
    class Machop(object):
      element = 'fighting'
      weight = 75

    @pokedex.register
    class Bellsprout(object):
      element = 'grass'
      weight = 15

    assert list(pokedex.items()) == \
      [('grass', Bellsprout), ('fighting', Machop), ('rock', Geodude)]

    assert list(pokedex.keys()) == ['grass', 'fighting', 'rock']

    assert list(pokedex.values()) == [Bellsprout, Machop, Geodude]

In the above example, the code iterates over registered classes in ascending order by their `weight` attributes.

You can provide a sorting function instead, if you need more control over how the items are sorted:

    from functools import cmp_to_key

    def sorter(a, b):
      """
      Sorts items by weight, using registry key as a tiebreaker.

      :param a: Tuple of (key, class)
      :param b: Tuple of (key, class)
      """
      # Sort descending by weight first.
      weight_cmp = (
          (a[1].weight < b[1].weight)
        - (a[1].weight > b[1].weight)
      )

      if weight_cmp != 0:
        return weight_cmp

      # Use registry key as a fallback.
      return ((a[0] > b[0]) - (a[0] < b[0]))

    pokedex =\
      SortedClassRegistry(
        attr_name = 'element',

        # Note that we pass ``sorter`` through ``cmp_to_key`` first!
        sort_key = cmp_to_key(sorter),
      )

    @pokedex.register
    class Horsea(object):
      element = 'water'
      weight = 5

    @pokedex.register
    class Koffing(object):
      element = 'poison'
      weight = 20

    @pokedex.register
    class Voltorb(object):
      element = 'electric'
      weight = 5

    assert list(pokedex.items()) == \
      [('poison', Koffing), ('electric', Voltorb), ('water', Horsea)]

    assert list(pokedex.keys()) == ['poison', 'electric', 'water']

    assert list(pokedex.values()) == [Koffing, Voltorb, Horsea]

This time, the `SortedClassRegistry` used our custom sorter function, so that the classes were sorted descending by weight, with the registry key used as a tiebreaker.

Important

Note that we had to pass the sorter function through `functools.cmp_to_key()` before providing it to the `SortedClassRegistry` initializer.

This is necessary because of how sorting works in Python. See Sorting HOW TO for more information.