Re: [Python-ideas] Draft PEP on string interpolation
![](https://secure.gravatar.com/avatar/3b73b776444fa777acfa37bbdcff23fe.jpg?s=120&d=mm&r=g)
On Sat Aug 29 18:41:55 CEST 2015, Ron Adam wrote:
One is nested evaluations, but that may be fixable.
Nesting arguments and more complex examples:
>>> for align, text in zip('<^>', ['left', 'center', 'right']): ... '{0:{fill}{align}16}'.format(text, fill=align, align=align) ... 'left<<<<<<<<<<<<' '^^^^^center^^^^^' '>>>>>>>>>>>right'
I haven't gotten this example to work yet.
I've deployed an implementation of my interpretation of PEP-498 in our 2.7 production code, tested in 3.4. Here's the function and your test case working properly: #!/bin/env python from __future__ import print_function, division import sys as _sys try: import _string # Py3 def _parseFormat(string): return _string.formatter_parser(string) unicode = str except ImportError: # Py2 def _parseFormat(string): return string._formatter_parser() def _stringInterpolater(s, depth=1, evalCallback=None, context=None, **kwds): """ $uuid:4cbb6191-464a-56dd-88e2-52f4f861527e$ Experimental implementation of the behavior described in https://www.python.org/dev/peps/pep-0498/ The first extension, ``depth``, allows for reimplementation from a function that looks deeper into the call stack for the "current" context (see ``printi``, below). The second extension, ``evalCallback``, allows us to intercept the value before formatting so that we can, for example, convert a Marker object to an Adams id (see Simulatable.formatFunction for details). ``context`` allows the user to pass a dictionary to completely replace the namespace calculations performed below. It too gets superseded by ``kwds``. """ # Local frame is needed for error reporting, so calculate it even # when the user supplies a context. localFrame = _sys._getframe() while depth: localFrame = localFrame.f_back depth -= 1 if context: localDict = kwds globalDict = context.copy() else: localDict = localFrame.f_locals.copy() # Must copy to avoid side effects. localDict.update(kwds) # Our **kwds override locals. globalDict = localFrame.f_globals def doFormat(formatString): """ $uuid:7c45191f-741b-51a0-b75a-a534e99f58cb$ """ result = list() for text, expression, formatSpec, conversion in _parseFormat(formatString): if text: result.append(text) if expression is None: break value = eval(expression, globalDict, localDict) if evalCallback: value = evalCallback(value) if conversion == "r": if isinstance(value, unicode): # Delete this check in Py3. value = str(value) # Eat the annoying "u" prefix in Py2. value = repr(value) elif conversion == "s": value = str(value) formatSpec = doFormat(formatSpec) # Recurse to evaluate embedded formats. try: result.append(format(value, formatSpec)) except ValueError as e: raise ValueError("{}, object named '{}'".format(str(e), expression), localFrame) return "".join(result) return doFormat(s) f = _stringInterpolater def printi(*args, **kwds): """ $uuid:15cccafc-f4ae-58df-ab3e-03553e567bf0$ """ sep = kwds.pop("sep", " ") # Py2 smell, in Py3 you'd just put them in the signature. end = kwds.pop("end", "\n") file = kwds.pop("file", _sys.stdout) newArgs = list() for arg in args: if isinstance(arg, (str, unicode)): newArgs.append(f(arg, depth=2, **kwds)) print(*newArgs, sep=sep, end=end, file=file) if __name__ == "__main__": strings = { "<" : "left ", "^" : " center ", ">" : " right", } width = 2*5 + max(len(s) for s in strings.values()) for align in strings: fill = align print(f("{strings[align]:{fill}{align}{width}}")) printi("{strings[align]:{fill}{align}{width}}")
participants (1)
-
Eric Fahlgren