[pypy-svn] r67547 - pypy/trunk/pypy/module/__builtin__
benjamin at codespeak.net
benjamin at codespeak.net
Sun Sep 6 22:28:19 CEST 2009
Author: benjamin
Date: Sun Sep 6 22:28:16 2009
New Revision: 67547
Modified:
pypy/trunk/pypy/module/__builtin__/__init__.py
pypy/trunk/pypy/module/__builtin__/app_functional.py
pypy/trunk/pypy/module/__builtin__/functional.py
Log:
reimplement min, max, reduce, sum, filter, map, zip, enumerate, and reversed on
the interp level for speed
Modified: pypy/trunk/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/__builtin__/__init__.py (original)
+++ pypy/trunk/pypy/module/__builtin__/__init__.py Sun Sep 6 22:28:16 2009
@@ -27,23 +27,11 @@
'raw_input' : 'app_io.raw_input',
'input' : 'app_io.input',
- 'sum' : 'app_functional.sum',
'apply' : 'app_functional.apply',
- 'map' : 'app_functional.map',
- 'filter' : 'app_functional.filter',
- 'zip' : 'app_functional.zip',
- 'reduce' : 'app_functional.reduce',
#'range' : 'app_functional.range',
# redirected to functional.py, applevel version
# is still needed and should stay where it is.
- 'min' : 'app_functional.min',
- 'max' : 'app_functional.max',
- 'enumerate' : 'app_functional.enumerate',
'sorted' : 'app_functional.sorted',
- 'reversed' : 'app_functional.reversed',
- '_install_pickle_support_for_reversed_iterator':
- 'app_functional._install_pickle_support_for_reversed_iterator',
-
'globals' : 'app_inspect.globals',
'locals' : 'app_inspect.locals',
'vars' : 'app_inspect.vars',
@@ -106,8 +94,17 @@
'range' : 'functional.range_int',
'xrange' : 'functional.W_XRange',
+ 'enumerate' : 'functional.W_Enumerate',
'all' : 'functional.all',
'any' : 'functional.any',
+ 'min' : 'functional.min',
+ 'max' : 'functional.max',
+ 'sum' : 'functional.sum',
+ 'map' : 'functional.map',
+ 'zip' : 'functional.zip',
+ 'reduce' : 'functional.reduce',
+ 'reversed' : 'functional.reversed',
+ 'filter' : 'functional.filter',
'super' : 'descriptor.W_Super',
'staticmethod' : 'descriptor.StaticMethod',
'classmethod' : 'descriptor.ClassMethod',
Modified: pypy/trunk/pypy/module/__builtin__/app_functional.py
==============================================================================
--- pypy/trunk/pypy/module/__builtin__/app_functional.py (original)
+++ pypy/trunk/pypy/module/__builtin__/app_functional.py Sun Sep 6 22:28:16 2009
@@ -3,151 +3,12 @@
functional programming.
"""
-
-def sum(sequence, total=0):
- """sum(sequence, start=0) -> value
-
-Returns the sum of a sequence of numbers (NOT strings) plus the value
-of parameter 'start'. When the sequence is empty, returns start."""
- # must forbid "summing" strings, per specs of built-in 'sum'
- if isinstance(total, str): raise TypeError
- for item in sequence:
- total = total + item
- return total
-
# ____________________________________________________________
def apply(function, args=(), kwds={}):
"""call a function (or other callable object) and return its result"""
return function(*args, **kwds)
-def map(function, *collections):
- """does 3 separate things, hence this enormous docstring.
- 1. if function is None, return a list of tuples, each with one
- item from each collection. If the collections have different
- lengths, shorter ones are padded with None.
-
- 2. if function is not None, and there is only one collection,
- apply function to every item in the collection and return a
- list of the results.
-
- 3. if function is not None, and there are several collections,
- repeatedly call the function with one argument from each
- collection. If the collections have different lengths,
- shorter ones are padded with None
- """
-
- if len(collections) == 0:
- raise TypeError, "map() requires at least one sequence"
-
- if len(collections) == 1:
- #it's the most common case, so make it faster
- if function is None:
- return list(collections[0])
- return [function(x) for x in collections[0]]
-
- iterators = [ iter(collection) for collection in collections ]
- res = []
- while 1:
- cont = False #is any collection not empty?
- args = []
- for iterator in iterators:
- try:
- elem = iterator.next()
- cont = True
- except StopIteration:
- elem = None
- args.append(elem)
- if cont:
- if function is None:
- res.append(tuple(args))
- else:
- res.append(function(*args))
- else:
- return res
-
-def filterstring(function, collection, str_type):
- if function is None and type(collection) is str_type:
- return collection
- res = []
- for i in xrange(len(collection)):
- c = collection[i]
- if function is None or function(c):
- if not isinstance(c, str_type):
- raise TypeError("can't filter %s to %s: __getitem__ returned different type", str_type.__name__, str_type.__name__)
- res.append(c)
- return str_type().join(res)
-
-def filtertuple(function, collection):
- if function is None:
- function = bool
- res = []
- for i in xrange(len(collection)):
- c = collection[i]
- if function(c):
- res.append(c)
- return tuple(res)
-
-def filter(function, collection):
- """construct a list of those elements of collection for which function
- is True. If function is None, then return the items in the sequence
- which are True."""
- if isinstance(collection, str):
- return filterstring(function, collection, str)
- elif isinstance(collection, unicode):
- return filterstring(function, collection, unicode)
- elif isinstance(collection, tuple):
- return filtertuple(function, collection)
-
- if function is None:
- return [item for item in collection if item]
- else:
- return [item for item in collection if function(item)]
-
-def zip(*collections):
- """return a list of tuples, where the nth tuple contains every
- nth item of each collection. If the collections have different
- lengths, zip returns a list as long as the shortest collection,
- ignoring the trailing items in the other collections."""
-
- if len(collections) == 0:
- import sys
- if sys.version_info < (2,4):
- raise TypeError("zip() requires at least one sequence")
- return []
- res = []
- iterators = [ iter(collection) for collection in collections ]
- while 1:
- try:
- elems = []
- for iterator in iterators:
- elems.append(iterator.next())
- res.append(tuple(elems))
- except StopIteration:
- return res
-
-def reduce(function, seq, *initialt):
- """ Apply function of two arguments cumulatively to the items of
- sequence, from left to right, so as to reduce the sequence to a
- single value. Optionally begin with an initial value."""
-
- seqiter = iter(seq)
- if initialt:
- initial, = initialt
- else:
- try:
- initial = seqiter.next()
- except StopIteration:
- raise TypeError, "reduce() of empty sequence with no initial value"
- while 1:
- try:
- arg = seqiter.next()
- except StopIteration:
- break
- initial = function(initial, arg)
-
- return initial
-
# ____________________________________________________________
"""
@@ -206,135 +67,10 @@
# ____________________________________________________________
-
-def _identity(arg):
- return arg
-
-
-def min(*arr, **kwargs):
- """return the smallest number in a list,
- or its smallest argument if more than one is given."""
- from operator import gt
-
- return min_max(gt, "min", *arr, **kwargs)
-
-def min_max(comp, funcname, *arr, **kwargs):
- key = kwargs.pop("key", _identity)
- if len(kwargs):
- raise TypeError, '%s() got an unexpected keyword argument' % funcname
-
- if not arr:
- raise TypeError, '%s() takes at least one argument' % funcname
-
- if len(arr) == 1:
- arr = arr[0]
-
- iterator = iter(arr)
- try:
- min_max_val = iterator.next()
- except StopIteration:
- raise ValueError, '%s() arg is an empty sequence' % funcname
-
- keyed_min_max_val = key(min_max_val)
-
- for i in iterator:
- keyed = key(i)
- if comp(keyed_min_max_val, keyed):
- min_max_val = i
- keyed_min_max_val = keyed
- return min_max_val
-
-def max(*arr, **kwargs):
- """return the largest number in a list,
- or its largest argument if more than one is given."""
- from operator import lt
-
- return min_max(lt, "max", *arr, **kwargs)
-
-class enumerate(object):
- """enumerate(iterable) -> iterator for (index, value) of iterable.
-
-Return an enumerate object. iterable must be an other object that supports
-iteration. The enumerate object yields pairs containing a count (from
-zero) and a value yielded by the iterable argument. enumerate is useful
-for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ..."""
-
- def __init__(self, collection):
- self._iter = iter(collection)
- self._index = 0
-
- def next(self):
- try:
- next = self._iter.next
- except AttributeError:
- # CPython raises a TypeError when next() is not defined
- raise TypeError('%s object has no next() method' %
- (type(self._iter).__name__,))
- result = self._index, next()
- self._index += 1
- return result
-
- def __iter__(self):
- return self
-
-
-# ____________________________________________________________
-
def sorted(lst, cmp=None, key=None, reverse=None):
"sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list"
sorted_lst = list(lst)
sorted_lst.sort(cmp, key, reverse)
return sorted_lst
-def reversed(sequence):
- "reversed(sequence) -> reverse iterator over values of the sequence"
- if hasattr(sequence, '__reversed__'):
- return sequence.__reversed__()
- if not hasattr(sequence, '__getitem__'):
- raise TypeError("argument to reversed() must be a sequence")
- return reversed_iterator(sequence)
-
-
-class reversed_iterator(object):
-
- def __init__(self, seq):
- self.seq = seq
- self.remaining = len(seq)
-
- def __iter__(self):
- return self
-
- def next(self):
- if self.remaining > len(self.seq):
- self.remaining = 0
- i = self.remaining
- if i > 0:
- i -= 1
- item = self.seq[i]
- self.remaining = i
- return item
- raise StopIteration
-
-# XXX __length_hint__()
-## def __len__(self):
-## if self.remaining > len(self.seq):
-## self.remaining = 0
-## return self.remaining
-
- def __reduce__(self):
- tup = (self.seq, self.remaining)
- return (make_reversed_iterator, tup)
-
-def make_reversed_iterator(seq, remaining):
- ri = reversed_iterator.__new__(reversed_iterator)
- ri.seq = seq
- #or "ri = reversed_iterator(seq)" but that executes len(seq)
- ri.remaining = remaining
- return ri
-
-def _install_pickle_support_for_reversed_iterator():
- import _pickle_support
- make_reversed_iterator.__module__ = '_pickle_support'
- _pickle_support.make_reversed_iterator = make_reversed_iterator
-
Modified: pypy/trunk/pypy/module/__builtin__/functional.py
==============================================================================
--- pypy/trunk/pypy/module/__builtin__/functional.py (original)
+++ pypy/trunk/pypy/module/__builtin__/functional.py Sun Sep 6 22:28:16 2009
@@ -8,7 +8,9 @@
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.argument import Arguments
from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.rlib.objectmodel import specialize
from pypy.module.__builtin__.app_functional import range as app_range
from inspect import getsource, getfile
@@ -100,7 +102,244 @@
return W_ListMultiObject(space, impl)
+ at specialize.arg(2)
+def min_max(space, arguments, implementation_of):
+ if implementation_of == "max":
+ compare = space.gt
+ else:
+ compare = space.lt
+ args, kwargs = arguments.unpack()
+ if len(args) > 1:
+ w_sequence = space.newtuple(args)
+ elif len(args):
+ w_sequence = args[0]
+ else:
+ msg = "%s() expects at least one argument" % (implementation_of,)
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ try:
+ w_key = kwargs["key"]
+ except KeyError:
+ w_key = None
+ else:
+ del kwargs["key"]
+ if kwargs:
+ msg = "%s() got unexpected keyword argument" % (implementation_of,)
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ w_iter = space.iter(w_sequence)
+ w_max_item = None
+ w_max_val = None
+ while True:
+ try:
+ w_item = space.next(w_iter)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break
+ if w_key is not None:
+ w_compare_with = space.call_function(w_key, w_item)
+ else:
+ w_compare_with = w_item
+ if w_max_item is None or \
+ space.is_true(compare(w_compare_with, w_max_val)):
+ w_max_item = w_item
+ w_max_val = w_compare_with
+ if w_max_item is None:
+ msg = "arg is an empty sequence"
+ raise OperationError(space.w_ValueError, space.wrap(msg))
+ return w_max_item
+def max(space, __args__):
+ """Return the largest item in a sequence.
+
+ If more than one argument is passed, return the maximum of them.
+ """
+ return min_max(space, __args__, "max")
+max.unwrap_spec = [ObjSpace, Arguments]
+
+def min(space, __args__):
+ """Return the smallest item in a sequence.
+
+ If more than one argument is passed, return the minimum of them.
+ """
+ return min_max(space, __args__, "min")
+min.unwrap_spec = [ObjSpace, Arguments]
+
+def map(space, w_func, collections_w):
+ """does 3 separate things, hence this enormous docstring.
+ 1. if function is None, return a list of tuples, each with one
+ item from each collection. If the collections have different
+ lengths, shorter ones are padded with None.
+
+ 2. if function is not None, and there is only one collection,
+ apply function to every item in the collection and return a
+ list of the results.
+
+ 3. if function is not None, and there are several collections,
+ repeatedly call the function with one argument from each
+ collection. If the collections have different lengths,
+ shorter ones are padded with None
+ """
+ if not collections_w:
+ msg = "map() requires at least two arguments"
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ num_collections = len(collections_w)
+ none_func = space.is_w(w_func, space.w_None)
+ if none_func and num_collections == 1:
+ return space.call_function(space.w_list, collections_w[0])
+ result_w = []
+ iterators_w = [space.iter(w_seq) for w_seq in collections_w]
+ num_iterators = len(iterators_w)
+ while True:
+ cont = False
+ args_w = [space.w_None] * num_iterators
+ for i in range(len(iterators_w)):
+ try:
+ args_w[i] = space.next(iterators_w[i])
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ else:
+ cont = True
+ w_args = space.newtuple(args_w)
+ if cont:
+ if none_func:
+ result_w.append(w_args)
+ else:
+ w_res = space.call(w_func, w_args)
+ result_w.append(w_res)
+ else:
+ return space.newlist(result_w)
+map.unwrap_spec = [ObjSpace, W_Root, "args_w"]
+
+def sum(space, w_sequence, w_start=None):
+ if space.is_w(w_start, space.w_None):
+ w_start = space.wrap(0)
+ elif space.is_true(space.isinstance(w_start, space.w_basestring)):
+ msg = "sum() can't sum strings"
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ w_iter = space.iter(w_sequence)
+ w_last = w_start
+ while True:
+ try:
+ w_next = space.next(w_iter)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break
+ w_last = space.add(w_last, w_next)
+ return w_last
+sum.unwrap_spec = [ObjSpace, W_Root, W_Root]
+
+def zip(space, sequences_w):
+ """Return a list of tuples, where the nth tuple contains every nth item of
+ each collection.
+
+ If the collections have different lengths, zip returns a list as long as the
+ shortest collection, ignoring the trailing items in the other collections.
+ """
+ if not sequences_w:
+ return space.newlist([])
+ result_w = []
+ iterators_w = [space.iter(w_seq) for w_seq in sequences_w]
+ while True:
+ try:
+ items_w = [space.next(w_it) for w_it in iterators_w]
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ return space.newlist(result_w)
+ result_w.append(space.newtuple(items_w))
+zip.unwrap_spec = [ObjSpace, "args_w"]
+
+def reduce(space, w_func, w_sequence, rest_w):
+ """ Apply function of two arguments cumulatively to the items of sequence,
+ from left to right, so as to reduce the sequence to a single value.
+ Optionally begin with an initial value.
+ """
+ w_iter = space.iter(w_sequence)
+ if rest_w:
+ if len(rest_w) > 1:
+ msg = "reduce() takes only 3 possible arguments"
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ w_initial, = rest_w
+ else:
+ try:
+ w_initial = space.next(w_iter)
+ except OperationError, e:
+ if e.match(space, space.w_StopIteration):
+ msg = "reduce() of empty sequence with no initial value"
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ raise
+ w_result = w_initial
+ while True:
+ try:
+ w_next = space.next(w_iter)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break
+ w_result = space.call_function(w_func, w_result, w_next)
+ return w_result
+reduce.unwrap_spec = [ObjSpace, W_Root, W_Root, "args_w"]
+
+def filter(space, w_func, w_seq):
+ """construct a list of those elements of collection for which function
+ is True. If function is None, then return the items in the sequence
+ which are True.
+ """
+ if space.is_true(space.isinstance(w_seq, space.w_str)):
+ return _filter_string(space, w_func, w_seq, space.w_str)
+ if space.is_true(space.isinstance(w_seq, space.w_unicode)):
+ return _filter_string(space, w_func, w_seq, space.w_unicode)
+ if space.is_true(space.isinstance(w_seq, space.w_tuple)):
+ return _filter_tuple(space, w_func, w_seq)
+ w_iter = space.iter(w_seq)
+ result_w = []
+ none_func = space.is_w(w_func, space.w_None)
+ while True:
+ try:
+ w_next = space.next(w_iter)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break
+ if none_func:
+ w_keep = w_next
+ else:
+ w_keep = space.call_function(w_func, w_next)
+ if space.is_true(w_keep):
+ result_w.append(w_next)
+ return space.newlist(result_w)
+
+def _filter_tuple(space, w_func, w_tuple):
+ none_func = space.is_w(w_func, space.w_None)
+ length = space.int_w(space.len(w_tuple))
+ result_w = []
+ for i in range(length):
+ w_item = space.getitem(w_tuple, space.wrap(i))
+ if none_func:
+ w_keep = w_item
+ else:
+ w_keep = space.call_function(w_func, w_item)
+ if space.is_true(w_keep):
+ result_w.append(w_item)
+ return space.newtuple(result_w)
+
+def _filter_string(space, w_func, w_string, w_str_type):
+ none_func = space.is_w(w_func, space.w_None)
+ if none_func and space.is_w(space.type(w_string), w_str_type):
+ return w_string
+ length = space.int_w(space.len(w_string))
+ result_w = []
+ for i in range(length):
+ w_item = space.getitem(w_string, space.wrap(i))
+ if none_func or space.is_true(space.call_function(w_func, w_item)):
+ if not space.is_true(space.isinstance(w_item, w_str_type)):
+ msg = "__getitem__ returned a non-string type"
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ result_w.append(w_item)
+ w_empty = space.call_function(w_str_type)
+ return space.call_method(w_empty, "join", space.newlist(result_w))
def all(space, w_S):
"""all(iterable) -> bool
@@ -138,6 +377,77 @@
any.unwrap_spec = [ObjSpace, W_Root]
+class W_Enumerate(Wrappable):
+
+ def __init__(self, w_iter, w_start):
+ self.w_iter = w_iter
+ self.w_index = w_start
+
+ def descr___new__(space, w_subtype, w_iterable):
+ self = space.allocate_instance(W_Enumerate, w_subtype)
+ self.__init__(space.iter(w_iterable), space.wrap(0))
+ return space.wrap(self)
+
+ def descr___iter__(self, space):
+ return space.wrap(self)
+ descr___iter__.unwrap_spec = ["self", ObjSpace]
+
+ def descr_next(self, space):
+ w_item = space.next(self.w_iter)
+ w_index = self.w_index
+ self.w_index = space.add(w_index, space.wrap(1))
+ return space.newtuple([w_index, w_item])
+ descr_next.unwrap_spec = ["self", ObjSpace]
+
+
+W_Enumerate.typedef = TypeDef("enumerate",
+ __new__=interp2app(W_Enumerate.descr___new__.im_func),
+ __iter__=interp2app(W_Enumerate.descr___iter__),
+ next=interp2app(W_Enumerate.descr_next),
+)
+
+
+def reversed(space, w_sequence):
+ """Return a iterator that yields items of sequence in reverse."""
+ w_reversed_descr = space.lookup(w_sequence, "__reversed__")
+ if w_reversed_descr is None:
+ return space.wrap(W_ReversedIterator(space, w_sequence))
+ return space.get_and_call_function(w_reversed_descr, w_sequence)
+reversed.unwrap_spec = [ObjSpace, W_Root]
+
+class W_ReversedIterator(Wrappable):
+
+ def __init__(self, space, w_sequence):
+ self.remaining = space.int_w(space.len(w_sequence)) - 1
+ self.w_sequence = w_sequence
+
+ def descr___iter__(self, space):
+ return space.wrap(self)
+ descr___iter__.unwrap_spec = ["self", ObjSpace]
+
+ def descr_next(self, space):
+ if self.remaining >= 0:
+ w_index = space.wrap(self.remaining)
+ try:
+ w_item = space.getitem(self.w_sequence, w_index)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ else:
+ self.remaining -= 1
+ return w_item
+
+ # Done
+ self.remaining = -1
+ raise OperationError(space.w_StopIteration, space.w_None)
+ descr_next.unwrap_spec = ["self", ObjSpace]
+
+W_ReversedIterator.typedef = TypeDef("reversed",
+ __iter__=interp2app(W_ReversedIterator.descr___iter__),
+ next=interp2app(W_ReversedIterator.descr_next),
+)
+
+
class W_XRange(Wrappable):
def __init__(self, space, start, len, step):
self.space = space
More information about the Pypy-commit
mailing list