# Author: Fred L. Drake, Jr.# fdrake@acm.org## This is a simple little module I wrote to make life easier. I didn't# see anything quite like it in the library, though I may have overlooked# something. I wrote this when I was trying to read some heavily nested# tuples with fairly non-descriptive content. This is modeled very much# after Lisp/Scheme - style pretty-printing of lists. If you find it# useful, thank small children who sleep at night."""Support to pretty-print lists, tuples, & dictionaries recursively.Very simple, but useful, especially in debugging data structures.Classes-------PrettyPrinter()Handle pretty-printing operations onto a stream using a configuredset of formatting parameters.Functions---------pformat()Format a Python object into a pretty-printed representation.pprint()Pretty-print a Python object to a stream [default is sys.stdout].saferepr()Generate a 'standard' repr()-like value, but protect against recursivedata structures."""import reimport sys as _sysfrom collections import OrderedDict as _OrderedDictfrom io import StringIO as _StringIO__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr","PrettyPrinter"]def pprint(object, stream=None, indent=1, width=80, depth=None, *,compact=False):"""Pretty-print a Python object to a stream [default is sys.stdout]."""printer = PrettyPrinter(stream=stream, indent=indent, width=width, depth=depth,compact=compact)printer.pprint(object)def pformat(object, indent=1, width=80, depth=None, *, compact=False):"""Format a Python object into a pretty-printed representation."""return PrettyPrinter(indent=indent, width=width, depth=depth,compact=compact).pformat(object)def saferepr(object):"""Version of repr() which can handle recursive data structures."""return _safe_repr(object, {}, None, 0)[0]def isreadable(object):"""Determine if saferepr(object) is readable by eval()."""return _safe_repr(object, {}, None, 0)[1]def isrecursive(object):"""Determine if object requires a recursive representation."""return _safe_repr(object, {}, None, 0)[2]class _safe_key:"""Helper function for key functions when sorting unorderable objects.The wrapped-object will fallback to an Py2.x style comparison forunorderable types (sorting first comparing the type name and then bythe obj ids). Does not work recursively, so dict.items() must have_safe_key applied to both the key and the value."""__slots__ = ['obj']def __init__(self, obj):self.obj = objdef __lt__(self, other):try:rv = self.obj.__lt__(other.obj)except TypeError:rv = NotImplementedif rv is NotImplemented:rv = (str(type(self.obj)), id(self.obj)) < \(str(type(other.obj)), id(other.obj))return rvdef _safe_tuple(t):"Helper function for comparing 2-tuples"return _safe_key(t[0]), _safe_key(t[1])class PrettyPrinter:def __init__(self, indent=1, width=80, depth=None, stream=None, *,compact=False):"""Handle pretty printing operations onto a stream using a set ofconfigured parameters.indentNumber of spaces to indent for each level of nesting.widthAttempted maximum number of columns in the output.depthThe maximum depth to print out nested structures.streamThe desired output stream. If omitted (or false), the standardoutput stream available at construction will be used.compactIf true, several items will be combined in one line."""indent = int(indent)width = int(width)assert indent >= 0, "indent must be >= 0"assert depth is None or depth > 0, "depth must be > 0"assert width, "width must be != 0"self._depth = depthself._indent_per_level = indentself._width = widthif stream is not None:self._stream = streamelse:self._stream = _sys.stdoutself._compact = bool(compact)def pprint(self, object):self._format(object, self._stream, 0, 0, {}, 0)self._stream.write("\n")def pformat(self, object):sio = _StringIO()self._format(object, sio, 0, 0, {}, 0)return sio.getvalue()def isrecursive(self, object):return self.format(object, {}, 0, 0)[2]def isreadable(self, object):s, readable, recursive = self.format(object, {}, 0, 0)return readable and not recursivedef _format(self, object, stream, indent, allowance, context, level):level = level + 1objid = id(object)if objid in context:stream.write(_recursion(object))self._recursive = Trueself._readable = Falsereturnrep = self._repr(object, context, level - 1)typ = type(object)max_width = self._width - 1 - indent - allowancesepLines = len(rep) > max_widthwrite = stream.writeif sepLines:r = getattr(typ, "__repr__", None)if issubclass(typ, dict):write('{')if self._indent_per_level > 1:write((self._indent_per_level - 1) * ' ')length = len(object)if length:context[objid] = 1indent = indent + self._indent_per_levelif issubclass(typ, _OrderedDict):items = list(object.items())else:items = sorted(object.items(), key=_safe_tuple)key, ent = items[0]rep = self._repr(key, context, level)write(rep)write(': ')self._format(ent, stream, indent + len(rep) + 2,allowance + 1, context, level)if length > 1:for key, ent in items[1:]:rep = self._repr(key, context, level)write(',\n%s%s: ' % (' '*indent, rep))self._format(ent, stream, indent + len(rep) + 2,allowance + 1, context, level)indent = indent - self._indent_per_leveldel context[objid]write('}')returnif ((issubclass(typ, list) and r is list.__repr__) or(issubclass(typ, tuple) and r is tuple.__repr__) or(issubclass(typ, set) and r is set.__repr__) or(issubclass(typ, frozenset) and r is frozenset.__repr__)):length = len(object)if issubclass(typ, list):write('[')endchar = ']'elif issubclass(typ, tuple):write('(')endchar = ')'else:if not length:write(rep)returnif typ is set:write('{')endchar = '}'else:write(typ.__name__)write('({')endchar = '})'indent += len(typ.__name__) + 1object = sorted(object, key=_safe_key)if self._indent_per_level > 1:write((self._indent_per_level - 1) * ' ')if length:context[objid] = 1self._format_items(object, stream,indent + self._indent_per_level,allowance + 1, context, level)del context[objid]if issubclass(typ, tuple) and length == 1:write(',')write(endchar)returnif issubclass(typ, str) and len(object) > 0 and r is str.__repr__:chunks = []lines = object.splitlines(True)if level == 1:indent += 1max_width -= 2for i, line in enumerate(lines):rep = repr(line)if len(rep) <= max_width:chunks.append(rep)else:# A list of alternating (non-space, space) stringsparts = re.split(r'(\s+)', line) + ['']current = ''for i in range(0, len(parts), 2):part = parts[i] + parts[i+1]candidate = current + partif len(repr(candidate)) > max_width:if current:chunks.append(repr(current))current = partelse:current = candidateif current:chunks.append(repr(current))if len(chunks) == 1:write(rep)returnif level == 1:write('(')for i, rep in enumerate(chunks):if i > 0:write('\n' + ' '*indent)write(rep)if level == 1:write(')')returnwrite(rep)def _format_items(self, items, stream, indent, allowance, context, level):write = stream.writedelimnl = ',\n' + ' ' * indentdelim = ''width = max_width = self._width - indent - allowance + 2for ent in items:if self._compact:rep = self._repr(ent, context, level)w = len(rep) + 2if width < w:width = max_widthif delim:delim = delimnlif width >= w:width -= wwrite(delim)delim = ', 'write(rep)continuewrite(delim)delim = delimnlself._format(ent, stream, indent, allowance, context, level)def _repr(self, object, context, level):repr, readable, recursive = self.format(object, context.copy(),self._depth, level)if not readable:self._readable = Falseif recursive:self._recursive = Truereturn reprdef format(self, object, context, maxlevels, level):"""Format object for a specific context, returning a stringand flags indicating whether the representation is 'readable'and whether the object represents a recursive construct."""return _safe_repr(object, context, maxlevels, level)# Return triple (repr_string, isreadable, isrecursive).def _safe_repr(object, context, maxlevels, level):typ = type(object)if typ is str:if 'locale' not in _sys.modules:return repr(object), True, Falseif "'" in object and '"' not in object:closure = '"'quotes = {'"': '\\"'}else:closure = "'"quotes = {"'": "\\'"}qget = quotes.getsio = _StringIO()write = sio.writefor char in object:if char.isalpha():write(char)else:write(qget(char, repr(char)[1:-1]))return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, Falser = getattr(typ, "__repr__", None)if issubclass(typ, dict) and r is dict.__repr__:if not object:return "{}", True, Falseobjid = id(object)if maxlevels and level >= maxlevels:return "{...}", False, objid in contextif objid in context:return _recursion(object), False, Truecontext[objid] = 1readable = Truerecursive = Falsecomponents = []append = components.appendlevel += 1saferepr = _safe_repritems = sorted(object.items(), key=_safe_tuple)for k, v in items:krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)append("%s: %s" % (krepr, vrepr))readable = readable and kreadable and vreadableif krecur or vrecur:recursive = Truedel context[objid]return "{%s}" % ", ".join(components), readable, recursiveif (issubclass(typ, list) and r is list.__repr__) or \(issubclass(typ, tuple) and r is tuple.__repr__):if issubclass(typ, list):if not object:return "[]", True, Falseformat = "[%s]"elif len(object) == 1:format = "(%s,)"else:if not object:return "()", True, Falseformat = "(%s)"objid = id(object)if maxlevels and level >= maxlevels:return format % "...", False, objid in contextif objid in context:return _recursion(object), False, Truecontext[objid] = 1readable = Truerecursive = Falsecomponents = []append = components.appendlevel += 1for o in object:orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)append(orepr)if not oreadable:readable = Falseif orecur:recursive = Truedel context[objid]return format % ", ".join(components), readable, recursiverep = repr(object)return rep, (rep and not rep.startswith('<')), Falsedef _recursion(object):return ("<Recursion on %s with id=%s>"% (type(object).__name__, id(object)))def _perfcheck(object=None):import timeif object is None:object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000p = PrettyPrinter()t1 = time.time()_safe_repr(object, {}, None, 0)t2 = time.time()p.pformat(object)t3 = time.time()print("_safe_repr:", t2 - t1)print("pformat:", t3 - t2)if __name__ == "__main__":_perfcheck()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. Open source ecosystem
2. Collaboration, People, Software
3. Evaluation model