Mapping, with sequence as key, wildcard and subsequence matching

Ben Finney ben+python at benfinney.id.au
Wed Jul 15 21:51:07 EDT 2015


Howdy all,

What well-defined data type exists with the following properties:

* Mapping, key → value.

* Each key is a sequence (e.g. `tuple`) of items such as text strings.

* Items in a key may be the sentinel `ANY` value, which will match any
  value at that position.

* A key may specify that it will match *only* sequences of the same
  length.

* A key may specify that it will match sequences with arbitrarily many
  additional unspecified items.

If it matters: I'm using Python 2 to implement this.


The “match any item” type is simple enough; I'm aware of the
`unittest.mock.ANY` sentinel, and that meets my needs.

What I'm hoping to find is a general, existing, solution to the problem
of a mapping that uses keys which, in their value, encapsulate the fact
that the key does, or does not, match sequences of arbitrary length
longer than itself.

Example of what I'd like::

    from unittest import mock

    responses = SubsequenceMatchingType([
            ('foo', 'bar', 'baz'):
                "Simple three-argument command.",
            ('wibble', mock.ANY, 'wubble'):
                "Second argument ANY.",
            ('lorem', 'ipsum'):
                "Arbitrary trailing arguments.",
            ])

    responses[('foo', 'bar')]  # raises KeyError
    responses[('foo', 'bar', 'baz')]  # → "Simple three-argument command."
    responses[('foo', 'bar', 'baz', 'bork')]  # raises KeyError

    responses[('wibble', 'wobble')]  # raises KeyError
    responses[('wibble', 'wobble', 'wubble')]  # → "Second argument ANY."
    responses[('wibble', 'wobble', 'baz')]  # raises KeyError
    responses[('wibble', 'wobble', 'wubble', 'baz')]  # raises KeyError

    responses[('lorem',)]  # raises KeyError
    responses[('lorem', 'ipsum')]  # → "Arbitrary trailing arguments."
    responses[('lorem', 'ipsum', 'dolor', 'sit', 'amet')]  # → "Arbitrary trailing arguments."

So some kind of distinguishing feature needs to be added to those keys
which should match arbitrary trailing items: not ‘('foo', 'bar', 'baz')’
but ‘('lorem', 'ipsum')’.

The trouble I'm having is that the keys in the mapping, and the
candidate sequences, are simple tuples. Adding a sentinel item at the
end would make it a different sequence, and indistinguishable from
specifying an additional item at that position.

Is this a problem already solved (and implemented, and debugged!) in a
general form that I can use?

-- 
 \      “I am too firm in my consciousness of the marvelous to be ever |
  `\       fascinated by the mere supernatural …” —Joseph Conrad, _The |
_o__)                                                     Shadow-Line_ |
Ben Finney




More information about the Python-list mailing list