Author: Devin Jeanpierre <[email protected]>
Branch: 
Changeset: r83477:a13a0320f6f3
Date: 2016-03-31 16:15 -0700
http://bitbucket.org/pypy/pypy/changeset/a13a0320f6f3/

Log:    Make attrgetter a single type -- this brings PyPy in line with
        CPython.

        e.g. code that does "if type(x) is operator.attrgetter:" now works.
        (I'm sorry.)

        Tested with stupid benchmarks and there is no significant
        difference. e.g.:

        (in pypy/pypy/module/operator):

         $ pypy -m timeit -s 'import operator; a =
        operator.attrgetter("real"); items = range(10000)' 'for x in items:
        a(x)' 10000 loops, best of 3: 71.7 usec per loop

         $ pypy -m timeit -s 'import app_operator as operator; a =
        operator.attrgetter("real"); items = range(10000)' 'for x in items:
        a(x)' 10000 loops, best of 3: 66.7 usec per loop

         $ pypy -m timeit -s 'import app_operator as operator; a =
        operator.attrgetter("real"); item = 1' 'a(1)' 100000000 loops, best
        of 3: 0.0073 usec per loop

         $ pypy -m timeit -s 'import operator; a =
        operator.attrgetter("real"); item = 1' 'a(1)' 100000000 loops, best
        of 3: 0.00694 usec per loop

         $ pypy -m timeit -s 'import app_operator as operator; a =
        operator.attrgetter("real.real"); items = range(10000)' 'for x in
        items: a(x)' 1000 loops, best of 3: 501 usec per loop

         $ pypy -m timeit -s 'import operator; a =
        operator.attrgetter("real.real"); items = range(10000)' 'for x in
        items: a(x)' 1000 loops, best of 3: 504 usec per loop

         $ pypy -m timeit -s 'import operator; a =
        operator.attrgetter("real.real", "real"); items = range(10000)' 'for
        x in items: a(x)' 1000 loops, best of 3: 1.74 msec per loop

         $ pypy -m timeit -s 'import app_operator as operator; a =
        operator.attrgetter("real.real", "real"); items = range(10000)' 'for
        x in items: a(x)' 1000 loops, best of 3: 1.82 msec per loop

diff --git a/pypy/module/operator/app_operator.py 
b/pypy/module/operator/app_operator.py
--- a/pypy/module/operator/app_operator.py
+++ b/pypy/module/operator/app_operator.py
@@ -79,54 +79,45 @@
     else:
         return _resolve_attr_chain(chain, obj, idx + 1)
 
-
-class _simple_attrgetter(object):
-    def __init__(self, attr):
-        self._attr = attr
+class attrgetter(object):
+    def __init__(self, attr, *attrs):
+        if (
+            not isinstance(attr, basestring) or
+            not all(isinstance(a, basestring) for a in attrs)
+        ):
+            def _raise_typeerror(obj):
+                raise TypeError(
+                    "argument must be a string, not %r" % type(attr).__name__
+                )
+            self._call = _raise_typeerror
+        elif attrs:
+            self._multi_attrs = [
+                a.split(".") for a in [attr] + list(attrs)
+            ]
+            self._call = self._multi_attrgetter
+        elif "." not in attr:
+            self._simple_attr = attr
+            self._call = self._simple_attrgetter
+        else:
+            self._single_attr = attr.split(".")
+            self._call = self._single_attrgetter
 
     def __call__(self, obj):
-        return getattr(obj, self._attr)
+        return self._call(obj)
 
+    def _simple_attrgetter(self, obj):
+        return getattr(obj, self._simple_attr)
 
-class _single_attrgetter(object):
-    def __init__(self, attrs):
-        self._attrs = attrs
+    def _single_attrgetter(self, obj):
+        return _resolve_attr_chain(self._single_attr, obj)
 
-    def __call__(self, obj):
-        return _resolve_attr_chain(self._attrs, obj)
-
-
-class _multi_attrgetter(object):
-    def __init__(self, attrs):
-        self._attrs = attrs
-
-    def __call__(self, obj):
+    def _multi_attrgetter(self, obj):
         return tuple([
             _resolve_attr_chain(attrs, obj)
-            for attrs in self._attrs
+            for attrs in self._multi_attrs
         ])
 
 
-def attrgetter(attr, *attrs):
-    if (
-        not isinstance(attr, basestring) or
-        not all(isinstance(a, basestring) for a in attrs)
-    ):
-        def _raise_typeerror(obj):
-            raise TypeError(
-                "argument must be a string, not %r" % type(attr).__name__
-            )
-        return _raise_typeerror
-    if attrs:
-        return _multi_attrgetter([
-            a.split(".") for a in [attr] + list(attrs)
-        ])
-    elif "." not in attr:
-        return _simple_attrgetter(attr)
-    else:
-        return _single_attrgetter(attr.split("."))
-
-
 class itemgetter(object):
     def __init__(self, item, *items):
         self._single = not bool(items)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to