嗯,问题似乎出在Python 2.7中的旧式类和新式类之间。
在Python 3.4中,您可以看到使用对象和不使用对象之间的区别仅在于符号的加载(并不那么重要):
C:\TEMP>C:\Python34\python.exe
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:15:05) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> def a():
... class A(object): pass
...
>>> def b():
... class B(): pass
...
>>> import dis
>>> dis.dis(a)
2 0 LOAD_BUILD_CLASS
1 LOAD_CONST 1 (<code object A at 0x020B8F20, file "<stdin>", line 2>)
4 LOAD_CONST 2 ('A')
7 MAKE_FUNCTION 0
10 LOAD_CONST 2 ('A')
13 LOAD_GLOBAL 0 (object) # Extra step, not that expensive.
16 CALL_FUNCTION 3 (3 positional, 0 keyword pair)
19 STORE_FAST 0 (A)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
>>> dis.dis(b)
2 0 LOAD_BUILD_CLASS
1 LOAD_CONST 1 (<code object B at 0x020B8D40, file "<stdin>", line 2>)
4 LOAD_CONST 2 ('B')
7 MAKE_FUNCTION 0
10 LOAD_CONST 2 ('B')
13 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
16 STORE_FAST 0 (B)
19 LOAD_CONST 0 (None)
22 RETURN_VALUE
>>>
在Python 2.7中,您还需要涉及LOAD_TUPLE这一步骤:
C:\Users\jsargiot\Downloads\so>C:\Python27\python.exe
Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> def a():
... class A(object): pass
...
>>> def b():
... class B(): pass
...
>>> import dis
>>> dis.dis(a)
2 0 LOAD_CONST 1 ('A')
3 LOAD_GLOBAL 0 (object) # First extra step (just like 3.4)
6 BUILD_TUPLE 1 # Second extra step, expensive
9 LOAD_CONST 2 (<code object A at 01EAEA88, file "<stdin>", line 2>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_FAST 0 (A)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
>>> dis.dis(b)
2 0 LOAD_CONST 1 ('B')
3 LOAD_CONST 3 (())
6 LOAD_CONST 2 (<code object B at 01EB8EC0, file "<stdin>", line 2>)
9 MAKE_FUNCTION 0
12 CALL_FUNCTION 0
15 BUILD_CLASS
16 STORE_FAST 0 (B)
19 LOAD_CONST 0 (None)
22 RETURN_VALUE
>>>
timeit
调用了gc.disable()
导致的。因为类总是创建很多循环引用,禁用收集器意味着每个CLS
实例都不能被释放。你可以通过调用gc.get_objects()
来获取被跟踪的对象列表。如果不禁用GC而只是将每个CLS
实例附加到一个列表中以保持引用,则性能相似。谜题似乎在于为什么对Python 2来说,在这种情况下_PyObject_GC_Malloc
的性能要差得多。 - Eryk Sun