Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 49cc01e

Browse files
committed
Brute-force performance hackery; buys back about 20% of the time for
saferepr(), a bit less for pformat().
1 parent a765c12 commit 49cc01e

1 file changed

Lines changed: 165 additions & 121 deletions

File tree

Lib/pprint.py

Lines changed: 165 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@
4545
__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
4646
"PrettyPrinter"]
4747

48+
# cache these for faster access:
49+
_commajoin = ", ".join
50+
_sys_modules = sys.modules
51+
_id = id
52+
_len = len
53+
_type = type
54+
55+
4856
def pprint(object, stream=None):
4957
"""Pretty-print a Python object to a stream [default is sys.sydout]."""
5058
printer = PrettyPrinter(stream=stream)
@@ -56,15 +64,15 @@ def pformat(object):
5664

5765
def saferepr(object):
5866
"""Version of repr() which can handle recursive data structures."""
59-
return _safe_repr(object, {})[0]
67+
return _safe_repr(object, {}, None, 0)[0]
6068

6169
def isreadable(object):
6270
"""Determine if saferepr(object) is readable by eval()."""
63-
return _safe_repr(object, {})[1]
71+
return _safe_repr(object, {}, None, 0)[1]
6472

6573
def isrecursive(object):
6674
"""Determine if object requires a recursive representation."""
67-
return _safe_repr(object, {})[2]
75+
return _safe_repr(object, {}, None, 0)[2]
6876

6977
class PrettyPrinter:
7078
def __init__(self, indent=1, width=80, depth=None, stream=None):
@@ -108,73 +116,84 @@ def pformat(self, object):
108116

109117
def isrecursive(self, object):
110118
self.__recursive = 0
111-
self.pformat(object)
119+
self.__repr(object, {}, 0)
112120
return self.__recursive
113121

114122
def isreadable(self, object):
115123
self.__recursive = 0
116124
self.__readable = 1
117-
self.pformat(object)
125+
self.__repr(object, {}, 0)
118126
return self.__readable and not self.__recursive
119127

120128
def __format(self, object, stream, indent, allowance, context, level):
121129
level = level + 1
122-
if context.has_key(id(object)):
123-
object = _Recursion(object)
130+
objid = _id(object)
131+
if objid in context:
132+
stream.write(_recursion(object))
124133
self.__recursive = 1
134+
self.__readable = 0
135+
return
125136
rep = self.__repr(object, context, level - 1)
126-
objid = id(object)
127-
context[objid] = 1
128-
typ = type(object)
129-
sepLines = len(rep) > (self.__width - 1 - indent - allowance)
130-
131-
if sepLines and typ in (ListType, TupleType):
132-
# Pretty-print the sequence.
133-
stream.write((typ is ListType) and '[' or '(')
134-
if self.__indent_per_level > 1:
135-
stream.write((self.__indent_per_level - 1) * ' ')
136-
length = len(object)
137-
if length:
138-
indent = indent + self.__indent_per_level
139-
self.__format(object[0], stream, indent, allowance + 1,
140-
context, level)
141-
if length > 1:
142-
for ent in object[1:]:
143-
stream.write(',\n' + ' '*indent)
144-
self.__format(ent, stream, indent,
145-
allowance + 1, context, level)
146-
indent = indent - self.__indent_per_level
147-
if typ is TupleType and length == 1:
148-
stream.write(',')
149-
stream.write(((typ is ListType) and ']') or ')')
150-
151-
elif sepLines and typ is DictType:
152-
stream.write('{')
153-
if self.__indent_per_level > 1:
154-
stream.write((self.__indent_per_level - 1) * ' ')
155-
length = len(object)
156-
if length:
157-
indent = indent + self.__indent_per_level
158-
items = object.items()
159-
items.sort()
160-
key, ent = items[0]
161-
rep = self.__repr(key, context, level) + ': '
162-
stream.write(rep)
163-
self.__format(ent, stream, indent + len(rep),
164-
allowance + 1, context, level)
165-
if len(items) > 1:
166-
for key, ent in items[1:]:
167-
rep = self.__repr(key, context, level) + ': '
168-
stream.write(',\n' + ' '*indent + rep)
169-
self.__format(ent, stream, indent + len(rep),
170-
allowance + 1, context, level)
171-
indent = indent - self.__indent_per_level
172-
stream.write('}')
173-
174-
else:
175-
stream.write(rep)
176-
177-
del context[objid]
137+
typ = _type(object)
138+
sepLines = _len(rep) > (self.__width - 1 - indent - allowance)
139+
write = stream.write
140+
141+
if sepLines:
142+
if typ is DictType:
143+
write('{')
144+
if self.__indent_per_level > 1:
145+
write((self.__indent_per_level - 1) * ' ')
146+
length = _len(object)
147+
if length:
148+
context[objid] = 1
149+
indent = indent + self.__indent_per_level
150+
items = object.items()
151+
items.sort()
152+
key, ent = items[0]
153+
rep = self.__repr(key, context, level)
154+
write(rep)
155+
write(': ')
156+
self.__format(ent, stream, indent + _len(rep) + 2,
157+
allowance + 1, context, level)
158+
if length > 1:
159+
for key, ent in items[1:]:
160+
rep = self.__repr(key, context, level)
161+
write(',\n%s: %s' % (' '*indent, rep))
162+
self.__format(ent, stream, indent + _len(rep) + 2,
163+
allowance + 1, context, level)
164+
indent = indent - self.__indent_per_level
165+
del context[objid]
166+
write('}')
167+
return
168+
169+
if typ is ListType or typ is TupleType:
170+
if typ is ListType:
171+
write('[')
172+
endchar = ']'
173+
else:
174+
write('(')
175+
endchar = ')'
176+
if self.__indent_per_level > 1:
177+
write((self.__indent_per_level - 1) * ' ')
178+
length = _len(object)
179+
if length:
180+
context[objid] = 1
181+
indent = indent + self.__indent_per_level
182+
self.__format(object[0], stream, indent, allowance + 1,
183+
context, level)
184+
if length > 1:
185+
for ent in object[1:]:
186+
write(',\n' + ' '*indent)
187+
self.__format(ent, stream, indent,
188+
allowance + 1, context, level)
189+
indent = indent - self.__indent_per_level
190+
del context[objid]
191+
if typ is TupleType and length == 1:
192+
write(',')
193+
write(endchar)
194+
return
195+
196+
write(rep)
178197

179198
def __repr(self, object, context, level):
180199
repr, readable, recursive = _safe_repr(object, context,
@@ -187,80 +206,105 @@ def __repr(self, object, context, level):
187206

188207
# Return triple (repr_string, isreadable, isrecursive).
189208

190-
_have_module = sys.modules.has_key
191-
192-
def _safe_repr(object, context, maxlevels=None, level=0):
193-
level += 1
194-
typ = type(object)
195-
if not (typ in (DictType, ListType, TupleType, StringType) and object):
196-
rep = `object`
197-
return rep, (rep and (rep[0] != '<')), 0
198-
elif typ is StringType:
199-
if not _have_module('locale'):
209+
def _safe_repr(object, context, maxlevels, level):
210+
typ = _type(object)
211+
if typ is StringType:
212+
if 'locale' not in _sys_modules:
200213
return `object`, 1, 0
201214
if "'" in object and '"' not in object:
202215
closure = '"'
203216
quotes = {'"': '\\"'}
204217
else:
205218
closure = "'"
206219
quotes = {"'": "\\'"}
220+
qget = quotes.get
207221
sio = StringIO()
222+
write = sio.write
208223
for char in object:
209224
if char.isalpha():
210-
sio.write(char)
225+
write(char)
211226
else:
212-
sio.write(quotes.get(char, `char`[1:-1]))
213-
return closure + sio.getvalue() + closure, 1, 0
214-
215-
if context.has_key(id(object)):
216-
return `_Recursion(object)`, 0, 1
217-
objid = id(object)
218-
context[objid] = 1
219-
220-
readable = 1
221-
recursive = 0
222-
startchar, endchar = {ListType: "[]",
223-
TupleType: "()",
224-
DictType: "{}"}[typ]
225-
if maxlevels and level > maxlevels:
226-
with_commas = "..."
227-
readable = 0
228-
229-
elif typ is DictType:
227+
write(qget(char, `char`[1:-1]))
228+
return ("%s%s%s" % (closure, sio.getvalue(), closure)), 1, 0
229+
230+
if typ is DictType:
231+
if not object:
232+
return "{}", 1, 0
233+
objid = _id(object)
234+
if maxlevels and level > maxlevels:
235+
return "{...}", 0, objid in context
236+
if objid in context:
237+
return _recursion(object), 0, 1
238+
context[objid] = 1
239+
readable = 1
240+
recursive = 0
230241
components = []
242+
append = components.append
243+
level += 1
244+
saferepr = _safe_repr
231245
for k, v in object.iteritems():
232-
krepr, kreadable, krecur = _safe_repr(k, context, maxlevels,
233-
level)
234-
vrepr, vreadable, vrecur = _safe_repr(v, context, maxlevels,
235-
level)
236-
components.append("%s: %s" % (krepr, vrepr))
246+
krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
247+
vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
248+
append("%s: %s" % (krepr, vrepr))
237249
readable = readable and kreadable and vreadable
238-
recursive = recursive or krecur or vrecur
239-
with_commas = ", ".join(components)
240-
241-
else: # list or tuple
242-
assert typ in (ListType, TupleType)
250+
if krecur or vrecur:
251+
recursive = 1
252+
del context[objid]
253+
return "{%s}" % _commajoin(components), readable, recursive
254+
255+
if typ is ListType or typ is TupleType:
256+
if typ is ListType:
257+
if not object:
258+
return "[]", 1, 0
259+
format = "[%s]"
260+
elif _len(object) == 1:
261+
format = "(%s,)"
262+
else:
263+
if not object:
264+
return "()", 1, 0
265+
format = "(%s)"
266+
objid = _id(object)
267+
if maxlevels and level > maxlevels:
268+
return format % "...", 0, objid in context
269+
if objid in context:
270+
return _recursion(object), 0, 1
271+
context[objid] = 1
272+
readable = 1
273+
recursive = 0
243274
components = []
244-
for element in object:
245-
subrepr, subreadable, subrecur = _safe_repr(
246-
element, context, maxlevels, level)
247-
components.append(subrepr)
248-
readable = readable and subreadable
249-
recursive = recursive or subrecur
250-
if len(components) == 1 and typ is TupleType:
251-
components[0] += ","
252-
with_commas = ", ".join(components)
253-
254-
s = "%s%s%s" % (startchar, with_commas, endchar)
255-
del context[objid]
256-
return s, readable and not recursive, recursive
257-
258-
class _Recursion:
259-
# represent a recursive relationship; really only used for the __repr__()
260-
# method...
261-
def __init__(self, object):
262-
self.__repr = "<Recursion on %s with id=%s>" \
263-
% (type(object).__name__, id(object))
264-
265-
def __repr__(self):
266-
return self.__repr
275+
append = components.append
276+
level += 1
277+
for o in object:
278+
orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
279+
append(orepr)
280+
if not oreadable:
281+
readable = 0
282+
if orecur:
283+
recursive = 1
284+
del context[objid]
285+
return format % _commajoin(components), readable, recursive
286+
287+
rep = `object`
288+
return rep, (rep and not rep.startswith('<')), 0
289+
290+
291+
def _recursion(object):
292+
return ("<Recursion on %s with id=%s>"
293+
% (_type(object).__name__, _id(object)))
294+
295+
296+
def _perfcheck(object=None):
297+
import time
298+
if object is None:
299+
object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
300+
p = PrettyPrinter()
301+
t1 = time.time()
302+
_safe_repr(object, {}, None, 0)
303+
t2 = time.time()
304+
p.pformat(object)
305+
t3 = time.time()
306+
print "_safe_repr:", t2 - t1
307+
print "pformat:", t3 - t2
308+
309+
if __name__ == "__main__":
310+
_perfcheck()

0 commit comments

Comments
 (0)