Truncado a la izquierda usando python 3.5 str.format?

P: ¿Es posible crear una cadena de formato utilizando la syntax de formato de cadena de Python 3.5 para truncar a la izquierda?

Básicamente, lo que quiero hacer es tomar un git SHA:

"c1e33f6717b9d0125b53688d315aff9cf8dd9977" 

Y usando solo una cadena de formato, obtenga la pantalla solo los 8 caracteres correctos:

 "f8dd9977" 

Cosas que he intentado:

Sintaxis inválida

 >>> "{foo[-8:]}".format(foo="c1e33f6717b9d0125b53688d315aff9cf8dd9977") >>> "{foo[-8]}".format(foo="c1e33f6717b9d0125b53688d315aff9cf8dd9977") >>> "{:8.-8}".format("c1e33f6717b9d0125b53688d315aff9cf8dd9977") 

Resultado equivocado

 ### Results in first 8 not last 8. >>> "{:8.8}".format("c1e33f6717b9d0125b53688d315aff9cf8dd9977") 

Obras pero inflexibles y engorrosas.

 ### solution requires that bar is always length of 40. >>> bar="c1e33f6717b9d0125b53688d315aff9cf8dd9977" >>> "{foo[32]}{foo[33]}{foo[34]}{foo[35]}{foo[36]}{foo[37]}{foo[38]}{foo[39]}".format(foo=bar) 

Una pregunta similar fue hecha, pero nunca contestada . Sin embargo, el mío difiere en que estoy limitado a usar solo cadenas de formato, no tengo la capacidad de cambiar el rango del parámetro de entrada. Esto significa que la siguiente es una solución inaceptable:

 >>> bar="c1e33f6717b9d0125b53688d315aff9cf8dd9977" >>> "{0}".format(bar[-8:]) 

Un aspecto más que debo aclarar … lo anterior explica la forma más simple del problema. En el contexto real, el problema se expresa más correctamente como:

 >>> import os >>> "foo {git_sha}".format(**os.environ) 

Donde quiero left_truncate “git_sha” variable de entorno. Es cierto que esto es un poco más complejo que la forma más simple, pero si puedo resolver la más simple, puedo encontrar una manera de resolver la más compleja.

¿La subclasificación es una opción?

 foo="c1e33f6717b9d0125b53688d315aff9cf8dd9977" class CustomStr(str): def __format__(self, spec): if spec == 'trunc_left': return self[-8:] else: return super().__format__(spec) s = CustomStr(foo) print('{}'.format(s)) print('{:trunc_left}'.format(s)) 

A partir de ahí, puedes hacer algo trabajando así:

 import os class CustomStr(str): def __format__(self, spec): return self[-8:] class OsEnvironWrapper(dict): def __init__(self, environ): self.environ = environ def __getitem__(self, key): if key == 'git_sha': return CustomStr(self.environ[key]) else: return self.environ[key] os_environ = OsEnvironWrapper(os.environ) print('foo {git_sha}'.format(**os_environ)) 

Lo sé, la envoltura es apenas aceptable, pero puedes modificarla para que sea transparente emulando un tipo de contenedor correctamente.

[editar] Vea la solución de Jim para una variante que no hace una subclase como str o dict .

Así que aquí está mi solución, gracias a @JacquesGaudin y amigos en #Python por brindar mucha orientación …

 class MyStr(object): """Additional format string options.""" def __init__(self, obj): super(MyStr, self).__init__() self.obj = obj def __format__(self, spec): if spec.startswith("ltrunc."): offset = int(spec[7:]) return self.obj[offset:] else: return self.obj.__format__(spec) 

Así que esto funciona al hacer esto:

 >>> f = {k: MyStr(v) for k, v in os.environ.items()} >>> "{PATH:ltrunc.-8}".format(**f)