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

Skip to content

Commit ec569b7

Browse files
committed
Issue #2534: speed up isinstance() and issubclass() by 50-70%, so as to
match Python 2.5 speed despite the __instancecheck__ / __subclasscheck__ mechanism. In the process, fix a bug where isinstance() and issubclass(), when given a tuple of classes as second argument, were looking up __instancecheck__ / __subclasscheck__ on the tuple rather than on each type object. Reviewed by Benjamin Peterson and Raymond Hettinger.
1 parent e2dffc0 commit ec569b7

8 files changed

Lines changed: 201 additions & 96 deletions

File tree

Include/abstract.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,11 @@ PyAPI_FUNC(int) PyObject_IsSubclass(PyObject *object, PyObject *typeorclass);
12731273
/* issubclass(object, typeorclass) */
12741274

12751275

1276+
PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls);
1277+
1278+
PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls);
1279+
1280+
12761281
#ifdef __cplusplus
12771282
}
12781283
#endif

Lib/test/test_abc.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,21 @@ class B(object):
7575
pass
7676
b = B()
7777
self.assertEqual(issubclass(B, A), False)
78+
self.assertEqual(issubclass(B, (A,)), False)
7879
self.assertEqual(isinstance(b, A), False)
80+
self.assertEqual(isinstance(b, (A,)), False)
7981
A.register(B)
8082
self.assertEqual(issubclass(B, A), True)
83+
self.assertEqual(issubclass(B, (A,)), True)
8184
self.assertEqual(isinstance(b, A), True)
85+
self.assertEqual(isinstance(b, (A,)), True)
8286
class C(B):
8387
pass
8488
c = C()
8589
self.assertEqual(issubclass(C, A), True)
90+
self.assertEqual(issubclass(C, (A,)), True)
8691
self.assertEqual(isinstance(c, A), True)
92+
self.assertEqual(isinstance(c, (A,)), True)
8793

8894
def test_isinstance_invalidation(self):
8995
class A(metaclass=abc.ABCMeta):
@@ -92,22 +98,29 @@ class B:
9298
pass
9399
b = B()
94100
self.assertEqual(isinstance(b, A), False)
101+
self.assertEqual(isinstance(b, (A,)), False)
95102
A.register(B)
96103
self.assertEqual(isinstance(b, A), True)
104+
self.assertEqual(isinstance(b, (A,)), True)
97105

98106
def test_registration_builtins(self):
99107
class A(metaclass=abc.ABCMeta):
100108
pass
101109
A.register(int)
102110
self.assertEqual(isinstance(42, A), True)
111+
self.assertEqual(isinstance(42, (A,)), True)
103112
self.assertEqual(issubclass(int, A), True)
113+
self.assertEqual(issubclass(int, (A,)), True)
104114
class B(A):
105115
pass
106116
B.register(str)
107117
class C(str): pass
108118
self.assertEqual(isinstance("", A), True)
119+
self.assertEqual(isinstance("", (A,)), True)
109120
self.assertEqual(issubclass(str, A), True)
121+
self.assertEqual(issubclass(str, (A,)), True)
110122
self.assertEqual(issubclass(C, A), True)
123+
self.assertEqual(issubclass(C, (A,)), True)
111124

112125
def test_registration_edge_cases(self):
113126
class A(metaclass=abc.ABCMeta):
@@ -130,29 +143,40 @@ def test_registration_transitiveness(self):
130143
class A(metaclass=abc.ABCMeta):
131144
pass
132145
self.failUnless(issubclass(A, A))
146+
self.failUnless(issubclass(A, (A,)))
133147
class B(metaclass=abc.ABCMeta):
134148
pass
135149
self.failIf(issubclass(A, B))
150+
self.failIf(issubclass(A, (B,)))
136151
self.failIf(issubclass(B, A))
152+
self.failIf(issubclass(B, (A,)))
137153
class C(metaclass=abc.ABCMeta):
138154
pass
139155
A.register(B)
140156
class B1(B):
141157
pass
142158
self.failUnless(issubclass(B1, A))
159+
self.failUnless(issubclass(B1, (A,)))
143160
class C1(C):
144161
pass
145162
B1.register(C1)
146163
self.failIf(issubclass(C, B))
164+
self.failIf(issubclass(C, (B,)))
147165
self.failIf(issubclass(C, B1))
166+
self.failIf(issubclass(C, (B1,)))
148167
self.failUnless(issubclass(C1, A))
168+
self.failUnless(issubclass(C1, (A,)))
149169
self.failUnless(issubclass(C1, B))
170+
self.failUnless(issubclass(C1, (B,)))
150171
self.failUnless(issubclass(C1, B1))
172+
self.failUnless(issubclass(C1, (B1,)))
151173
C1.register(int)
152174
class MyInt(int):
153175
pass
154176
self.failUnless(issubclass(MyInt, A))
177+
self.failUnless(issubclass(MyInt, (A,)))
155178
self.failUnless(isinstance(42, A))
179+
self.failUnless(isinstance(42, (A,)))
156180

157181
def test_all_new_methods_are_called(self):
158182
class A(metaclass=abc.ABCMeta):

Lib/test/test_exceptions.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -582,12 +582,18 @@ class MyException(Exception, metaclass=Meta):
582582
except KeyError:
583583
pass
584584
except:
585-
self.fail("Should have raised TypeError")
585+
self.fail("Should have raised KeyError")
586586
else:
587-
self.fail("Should have raised TypeError")
588-
self.assertEqual(stderr.getvalue(),
589-
"Exception ValueError: ValueError() "
590-
"in <class 'KeyError'> ignored\n")
587+
self.fail("Should have raised KeyError")
588+
589+
def g():
590+
try:
591+
return g()
592+
except RuntimeError:
593+
return sys.exc_info()
594+
e, v, tb = g()
595+
self.assert_(isinstance(v, RuntimeError), type(v))
596+
self.assert_("maximum recursion depth exceeded" in str(v), str(v))
591597

592598

593599
def test_MemoryError(self):

Lib/test/test_typechecks.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,39 @@ def testIsSubclassInternal(self):
3333

3434
def testIsSubclassBuiltin(self):
3535
self.assertEqual(issubclass(int, Integer), True)
36+
self.assertEqual(issubclass(int, (Integer,)), True)
3637
self.assertEqual(issubclass(float, Integer), False)
38+
self.assertEqual(issubclass(float, (Integer,)), False)
3739

3840
def testIsInstanceBuiltin(self):
3941
self.assertEqual(isinstance(42, Integer), True)
42+
self.assertEqual(isinstance(42, (Integer,)), True)
4043
self.assertEqual(isinstance(3.14, Integer), False)
44+
self.assertEqual(isinstance(3.14, (Integer,)), False)
4145

4246
def testIsInstanceActual(self):
4347
self.assertEqual(isinstance(Integer(), Integer), True)
48+
self.assertEqual(isinstance(Integer(), (Integer,)), True)
4449

4550
def testIsSubclassActual(self):
4651
self.assertEqual(issubclass(Integer, Integer), True)
52+
self.assertEqual(issubclass(Integer, (Integer,)), True)
4753

4854
def testSubclassBehavior(self):
4955
self.assertEqual(issubclass(SubInt, Integer), True)
56+
self.assertEqual(issubclass(SubInt, (Integer,)), True)
5057
self.assertEqual(issubclass(SubInt, SubInt), True)
58+
self.assertEqual(issubclass(SubInt, (SubInt,)), True)
5159
self.assertEqual(issubclass(Integer, SubInt), False)
60+
self.assertEqual(issubclass(Integer, (SubInt,)), False)
5261
self.assertEqual(issubclass(int, SubInt), False)
62+
self.assertEqual(issubclass(int, (SubInt,)), False)
5363
self.assertEqual(isinstance(SubInt(), Integer), True)
64+
self.assertEqual(isinstance(SubInt(), (Integer,)), True)
5465
self.assertEqual(isinstance(SubInt(), SubInt), True)
66+
self.assertEqual(isinstance(SubInt(), (SubInt,)), True)
5567
self.assertEqual(isinstance(42, SubInt), False)
68+
self.assertEqual(isinstance(42, (SubInt,)), False)
5669

5770

5871
def test_main():

Misc/NEWS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ What's New in Python 3.0 release candidate 1
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #2534: speed up isinstance() and issubclass() by 50-70%, so as to
16+
match Python 2.5 speed despite the __instancecheck__ / __subclasscheck__
17+
mechanism. In the process, fix a bug where isinstance() and issubclass(),
18+
when given a tuple of classes as second argument, were looking up
19+
__instancecheck__ / __subclasscheck__ on the tuple rather than on each
20+
type object.
21+
1522
- Issue #3663: Py_None was decref'd when printing SyntaxErrors.
1623

1724
- Issue #3657: Fix uninitialized memory read when pickling longs.

0 commit comments

Comments
 (0)