python - una - Dejando los valores en blanco si no se pasa en formato str.
metodos de listas en python (5)
Me he encontrado con un problema bastante simple para el que no puedo encontrar una solución elegante.
Estoy creando una cadena usando str.format
en una función que se pasa en un dict
de sustituciones para usar para el formato. Quiero crear la cadena y formatearla con los valores si se pasan y dejarlos en blanco de lo contrario.
Ex
kwargs = {"name": "mark"}
"My name is {name} and I''m really {adjective}.".format(**kwargs)
debería regresar
"My name is mark and I''m really ."
en lugar de lanzar un KeyError
(que es lo que pasaría si no hacemos nada).
Avergonzado, ni siquiera puedo encontrar una solución poco elegante para este problema. Supongo que podría resolver esto simplemente no utilizando str.format
, pero prefiero usar el incorporado (que en su mayoría hace lo que quiero) si es posible.
Nota: No sé de antemano qué claves se utilizarán. Estoy tratando de fallar con gracia si alguien incluye una llave pero no la pone en el dictado de Kwargs. Si supiera con una precisión del 100% qué claves se buscarán, simplemente las rellenaré y terminaré con ellas.
Aquí hay una opción que usa collections.defaultdict
:
>>> from collections import defaultdict
>>> kwargs = {"name": "mark"}
>>> template = "My name is {0[name]} and I''m really {0[adjective]}."
>>> template.format(defaultdict(str, kwargs))
"My name is mark and I''m really ."
Tenga en cuenta que ya no estamos usando **
para descomprimir el diccionario en argumentos de palabras clave, y el especificador de formato usa {0[name]}
y {0[adjective]}
, lo que indica que debemos realizar una búsqueda de clave en el primer argumento format()
usando "name"
y "adjective"
respectivamente. Al usar defaultdict
una clave faltante dará como resultado una cadena vacía en lugar de elevar un KeyError.
Para el registro:
s = "My name is {name} and I''m really {adjective}."
kwargs = dict((x[1], '''') for x in s._formatter_parser())
# Now we have: `kwargs = {''name'':'''', ''adjective'':''''}`.
kwargs.update(name=''mark'')
print s.format(**kwargs) # My name is mark and I''m really .
Puede seguir la recomendación en PEP 3101 y usar un subclase Formateador:
import string
class BlankFormatter(string.Formatter):
def __init__(self, default=''''):
self.default=default
def get_value(self, key, args, kwds):
if isinstance(key, str):
return kwds.get(key, self.default)
else:
return string.Formatter.get_value(key, args, kwds)
kwargs = {"name": "mark", "adj": "mad"}
fmt=BlankFormatter()
print fmt.format("My name is {name} and I''m really {adj}.", **kwargs)
# My name is mark and I''m really mad.
print fmt.format("My name is {name} and I''m really {adjective}.", **kwargs)
# My name is mark and I''m really .
A partir de Python 3.2, puede utilizar .format_map como alternativa:
class Default(dict):
def __missing__(self, key):
return ''{''+key+''}''
kwargs = {"name": "mark"}
print("My name is {name} and I''m really {adjective}.".format_map(Default(kwargs)))
que imprime:
My name is mark and I''m really {adjective}.
Quería agregar una solución bastante simple a la sustitución de los valores predeterminados necesarios.
import string
class SafeDict(dict):
def __init__(self, missing=''#'', empty='''', *args, **kwargs):
super(SafeDict, self).__init__(*args, **kwargs)
self.missing = missing
self.empty = empty
def __getitem__(self, item):
return super(SafeDict, self).__getitem__(item) or self.empty
def __missing__(self, key):
return self.missing
values = SafeDict(a=None, c=1})
string.Formatter().vformat(''{a} {c} {d}'', (), values)
# '' 1 #''
Una forma de evitar el error clave es incluirlo en el dict pero dejarlo en blanco:
kwargs = {"name": "mark", "adjective": ""}
"My name is {name} and I''m really {adjective}.".format(**kwargs)
Los argumentos de las palabras clave esperan que sean claves en los kwargs. Otra forma de hacerlo sería con argumentos posicionales:
"My name is {0} and I''m really {1}.".format("mark")
Impresiones "Mi nombre es Mark y soy realmente". Mientras
"My name is {0} and I''m really {1}.".format("mark","black")
Impresiones "Mi nombre es Mark y soy realmente negro".
Alternativamente, puedes atrapar el ValueError.