Slicing strings in str.format

No, you can't apply slicing to strings inside a the replacement field.

You'll need to refer to the Format Specification Mini-Language; it defines what is possible. This mini language defines how you format the referenced value (the part after the : in the replacement field syntax).


You could do something like this.

NOTE
This is a rough example and should not be considered complete and tested. But I think it shows you a way to start getting where you want to be.

import string

class SliceFormatter(string.Formatter):

    def get_value(self, key, args, kwds):
        if '|' in key:
            try:
                key, indexes = key.split('|')
                indexes = map(int, indexes.split(','))
                if key.isdigit():
                    return args[int(key)][slice(*indexes)]
                return kwds[key][slice(*indexes)]
            except KeyError:
                return kwds.get(key, 'Missing')
        return super(SliceFormatter, self).get_value(key, args, kwds)


phrase = "Hello {name|0,5}, nice to meet you.  I am {name|6,9}.  That is {0|0,4}."
fmt = SliceFormatter()
print fmt.format(phrase, "JeffJeffJeff", name="Larry Bob")

OUTPUT

Hello Larry, nice to meet you.  I am Bob.  That is Jeff.

NOTE 2
There is no support for slicing like [:5] or [6:], but I think that would be easy enough to implement as well. Also there is no error checking for slice indexes out of range, etc.


You can use a run-time evaluated "f" string. Python f-strings support slicing and don't use a "mini-language" like the formatter. The full power of a python expression is available within each curly-brace of an f-string. Unfortunately there is no string.feval() function ... imo there should be (languages should not have magic abilities that are not provided to the user).

You also can't add one to the string type, because the built-in python types cannot be modified/expanded.

See https://stackoverflow.com/a/49884004/627042 for an example of a run-time evaluates f-string.


Straight answering your question: No, slicing is not supported by builtin str formatting. Although, there is a workaround in case f-strings (runtime evaluated) don't fit your needs.

Workaround

The previous answers to extend string.Formatter are not completely right, since overloading get_value is not the correct way to add the slicing mechanism to string.Formatter.

import string


def transform_to_slice_index(val: str):
    if val == "_":
        return None
    else:
        return int(val)


class SliceFormatter(string.Formatter):

    def get_field(self, field_name, args, kwargs):
        slice_operator = None
        if type(field_name) == str and '|' in field_name:
            field_name, slice_indexes = field_name.split('|')
            slice_indexes = map(transform_to_slice_index,
                                slice_indexes.split(','))
            slice_operator = slice(*slice_indexes)

        obj, first = super().get_field(field_name, args, kwargs)
        if slice_operator is not None:
            obj = obj[slice_operator]

        return obj, first

Explanation

get_value is called inside get_field and it is used ONLY to access the args and kwargs from vformat(). attr and item accessing is done in get_field. Thus, the slice access should be done after super().get_field returned the desired obj.

With this said, overloading get_value gives you the problem that the formatter would not work for slicing after the object is traversed. You can see the error in this example:

WrongSliceFormatter().format("{foo.bar[0]|1,3}", foo=foo)
>> ValueError: "Only '.' or '[' may follow ']' in format field specifier"