[Python-ideas] PEP pre-draft: Support for indexing with keyword arguments

Chris Angelico rosuav at gmail.com
Wed Jul 2 03:06:24 CEST 2014


On Wed, Jul 2, 2014 at 8:36 AM, Stefano Borini
<stefano.borini at ferrara.linux.it> wrote:
> https://github.com/stefanoborini/pep-keyword/blob/master/PEP-XXX.txt

A good start!

"""
        C0: a[1]        -> idx = 1        # integer
            a[1,2]      -> idx = (1,2)    # tuple
        C1: a[Z=3]      -> idx = {"Z": 3} # dictionary with single key
        C2. a[Z=3, R=4] -> idx = {"Z": 3, "R": 4}     #
dictionary/ordereddict [*]
                        or idx = ({"Z": 3}, {"R": 4}) # tuple of two
single-key dict [**]
...
        C5. a[1, 2, Z=3]   -> idx = (1, 2, {"Z": 3})
"""

Another possibility for the keyword arguments is a two-item tuple,
which would mean that C1 comes up as ("Z", 3) (or maybe (("Z", 3),) -
keyword arguments forcing a tuple of all args for
consistency/clarity), C2 as (("Z", 3), ("R", 4)), and C5 as (1, 2,
("Z", 3)). This would be lighter and easier to use than the tuple of
dicts, and still preserves order (unlike the regular dict); however,
it doesn't let you easily fetch up the one keyword you're interested
in, which is normally something you'd want to support for a
**kwargs-like feature:

def __getitem__(self, item, **kwargs):
    # either that, or kwargs is part of item in some way
    ret = self.base[item]
    if "precis" in kwargs: ret.round(kwargs["precis"])
    return ret

To implement that with a tuple of tuples, or a tuple of dicts, you'd
have to iterate over it and check each one - much less clean code.

I would be inclined to simply state, in the PEP, that keyword
arguments in indexing are equivalent to kwargs in function calls, and
equally unordered (that is to say: if a proposal to make function call
kwargs ordered is accepted, the same consideration can be applied to
this, but otherwise they have no order). This does mean that it
doesn't fit the original use-case, but it seems very odd to start out
by saying "here, let's give indexing the option to carry keyword args,
just like with function calls", and then come back and say "oh, but
unlike function calls, they're inherently ordered and carried very
differently".

For the OP's use-case, though, it would actually be possible to abuse
slice notation. I don't remember this being mentioned, but it does
preserve order; the cost is that all the "keywords" have to be defined
as objects.

class kw: pass # because object() doesn't have attributes
def make_kw(names):
    for i in names.split():
        globals()[i] = obj = kw()
        obj.keyword_arg = i
make_kw("Z R X")

# Now you can use them in indexing
some_obj[5, Z:3]
some_obj[7, Z:3, R:4]

The parameters will arrive in the item tuple as slice objects, where
the start is a signature object and the stop is its value.

>>> some_obj[5, Z:3]
getitem: (5, slice(<__main__.kw object at 0x016C5E10>, 3, None))

Yes, it uses a colon rather than an equals sign, but on the flip side,
it already works :)

ChrisA


More information about the Python-ideas mailing list