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