<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Mar 5, 2013 at 9:05 AM, Christian Heimes <span dir="ltr"><<a href="mailto:christian@python.org" target="_blank">christian@python.org</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hello,<br>
<br>
today I came across this slides<br>
<a href="https://speakerdeck.com/alex/why-python-ruby-and-javascript-are-slow" target="_blank">https://speakerdeck.com/alex/why-python-ruby-and-javascript-are-slow</a> by<br>
Alex Gaynor. The slides aren't some random rants on Python. Alex makes<br>
some valid points. Coincidentally  he is a PyPy developer, too. ;)<br>
<br>
One of his assertions is about memory (re)allocation. C is faster in<br>
some cases because C code usually does fewer allocations and<br>
reallocations. Python has no API to easily reallocate a list with 100<br>
items. Code like<br>
<br>
  lst = []<br>
  for i in range(100):<br>
      lst.append(i*i)<br>
<br>
has to resize the list multiple times. PyPy has a feature to create a<br>
preallocated list. <a href="https://bitbucket.org/pypy/pypy/commits/2ff5e3c765ef/" target="_blank">https://bitbucket.org/pypy/pypy/commits/2ff5e3c765ef/</a><br>
<br>
Internally CPython already distinguishes between the length of object<br>
and the allocation size of an object for some types like list, dict and<br>
bytearray. For example PyListObject has `ob_size` for __len__ and<br>
`allocated` for the amount of available `ob_item` slots.<br>
<br>
I suggest that we add two new functions to container types like list,<br>
bytearray and dict. obj.__preallocate__(size) increases the internal<br>
buffer by size elements. obj.__shrink__() dwindles the internal buffer<br>
to len(obj) elements, maybe a bit more.<br>
<br>
A new context manager aids users with preallocation and shrinking:<br>
<br>
class LengthHint:<br>
    def __init__(self, container, hint):<br>
        self.container = container<br>
        self.hint = hint<br>
        self.instance = None<br>
<br>
    def __enter__(self):<br>
        self.instance = self.container()<br>
        self.instance.__preallocate__(self.hint)<br>
        return self.instance<br>
<br>
    def __exit__(self, exc_type, exc_val, exc_tb):<br>
        self.instance.__shrink__()<br>
<br>
<br>
with LengthHint(list, 200) as lst:<br>
    # lst has 200 ob_item slots but len(lst) == 0<br>
    for i in range(100):<br>
        lst.append(i*i)<br>
# __exit__ shrinks ob_item to 100<br></blockquote></div><br>The real problem is that this code is not idiomatic Python, especially if you want it to be reasonably fast:<br><br>  lst = []<br>
  for i in range(100):<br>
      lst.append(i*i)<br><br></div><div class="gmail_extra">Why not:<br><br>lst = [i*i for i in range(100)]<br><br></div><div class="gmail_extra">If the "append" pattern is complex, just "preallocate" like this:<br>

<br></div><div class="gmail_extra">lst = [0] * 100<br><br></div><div class="gmail_extra">And then fill it.<br><br>Eli<br></div><div class="gmail_extra"><br></div></div>