pypy支持的擴(kuò)展模塊(對應(yīng)Python/Modules/
中的模塊)
-
pypy支持的內(nèi)建模塊:
-
__builtin__
:內(nèi)建模塊,包含一些常用的函數(shù),如abs()
等; -
__pypy__
:提供一個(gè)由pypy解析器提供的特殊功能模塊; -
_ast
:抽象句法樹模塊的內(nèi)建模塊,一般直接使用ast
模塊; -
_codecs
:注冊表與基類的編解碼器的內(nèi)建模塊,一般直接使用codecs
模塊; -
_collections
:容器數(shù)據(jù)類型的內(nèi)建模塊,一般直接使用collections
模塊; -
_continuation
: -
_ffi
: -
_hashlib
:安全散列與消息摘要的內(nèi)建模塊,一般直接使用hashlib
模塊; -
_io
:io內(nèi)建模塊,一般直接使用io
模塊; -
_locale
:國際化的內(nèi)建模塊,一般直接使用locale
模塊; -
_lsprof
:Python分析器的內(nèi)建模塊,一般直接使用lsprof
模塊; -
_md5
:md5的內(nèi)建模塊,一般直接使用md5
模塊; -
_minimal_curses
:字符顯示的終端處理curses的內(nèi)建模塊,一般直接使用curses
模塊,_minimal_curses
僅是一個(gè)殘留,只實(shí)現(xiàn)了部分功能,一般使用_curses
; -
_multiprocessing
:基于進(jìn)程的并行的multiprocessing
的內(nèi)建模塊,一般直接使用multiprocessing
模塊; -
_random
:生成偽隨機(jī)數(shù)的內(nèi)建模塊,一般直接使用random
模塊; -
_rawffi
:_rawffi是一個(gè)通過libffi來調(diào)用C的動態(tài)庫方法和創(chuàng)建C對象(數(shù)組或結(jié)構(gòu)體) 的內(nèi)建模塊; -
_sha
:SHA-1的內(nèi)建模塊,在pypy中還有sha
模塊,但是一般調(diào)用hashlib
,在Ptyhon2.7中sha
仍存在,但已經(jīng)是Deprecated,Python3.X中sha
已不再使用,一般直接使用hashlib
模塊; -
_socket
:Socket的內(nèi)建模塊,一般直接使用socket
模塊; -
_sre
:是實(shí)現(xiàn)正則表達(dá)式re
大部分功能的內(nèi)建模塊,一般直接使用re
模塊; -
_ssl
:TLS/SSL的內(nèi)建模塊,一般直接使用ssl
模塊; -
_warnings
:警告控制的內(nèi)建模塊,一般直接使用warnings
模塊; -
_weakref
:弱引用的內(nèi)建模塊,一般直接使用weakref
模塊; -
_winreg
:Windows注冊表訪問的內(nèi)建模塊,一般直接使用winreg
模塊; -
array
:高效數(shù)值數(shù)組的內(nèi)建模塊; -
binascii
:二進(jìn)制碼與ASCII碼間轉(zhuǎn)化的內(nèi)建模塊; -
bz2
:對bzip2壓縮支持的內(nèi)建模塊; -
cStringIO
:對內(nèi)存進(jìn)行文件操作(Read and write strings as files)的C實(shí)現(xiàn)的內(nèi)建模塊; -
cmath
:提供數(shù)學(xué)運(yùn)算的C實(shí)現(xiàn)的內(nèi)建模塊; -
cpyext
:cpyext內(nèi)建模塊提供讓pypy使用CPython的擴(kuò)展模塊; -
crypt
:Unix密碼驗(yàn)證的內(nèi)建模塊; -
errno
:標(biāo)準(zhǔn)錯(cuò)誤記號的內(nèi)建模塊; -
exceptions
:異常處理的內(nèi)建模塊; -
fcntl
:系統(tǒng)調(diào)用文件鎖fcntl()和ioctl()的內(nèi)建模塊; -
gc
:垃圾回收的內(nèi)建模塊; -
imp
:訪問import模塊接口的內(nèi)建模塊; -
itertools
:高效循環(huán)的迭代函數(shù)集合的內(nèi)建模塊; -
marshal
:序列化與反序列化的內(nèi)建模塊之一; -
math
:提供數(shù)學(xué)運(yùn)算的內(nèi)建模塊; -
mmap
:內(nèi)存映射文件支持的內(nèi)建模塊; -
operator
:針對函數(shù)標(biāo)準(zhǔn)操作的內(nèi)建模塊; -
parser
:訪問Python解析樹的內(nèi)建模塊; -
posix
:POSIX調(diào)用的內(nèi)建模塊; -
pyexpat
:解析xml的內(nèi)建模塊,一般直接使用xml
模塊;; -
select
:提供系統(tǒng)內(nèi)I/O多路復(fù)用的內(nèi)建模塊; -
struct
:將字節(jié)解析為打包的二進(jìn)制數(shù)據(jù)的內(nèi)建模塊; -
symbol
:Python解析樹中的常量的內(nèi)建模塊; -
sys
:系統(tǒng)相關(guān)的參數(shù)與函數(shù)的內(nèi)建模塊; -
termios
:POSIX風(fēng)格的tty控制的內(nèi)建模塊; -
thread
:線程的內(nèi)建模塊; -
time
:時(shí)間日期的內(nèi)建模塊; -
token
:Python解析樹中的常量的內(nèi)建模塊; -
unicodedata
:Unicode字符數(shù)據(jù)庫的內(nèi)建模塊; -
zipimport
:從ZIP歸檔中導(dǎo)入的內(nèi)建模塊; -
zlib
:兼容gzip壓縮的內(nèi)建模塊;
-
通過純Python重寫的模塊在 lib_pypy/ (部分使用了
cffi
),比如:ctypes
,cPickle
,cmath
,dbm
,datetime
;
垃圾回收機(jī)制(gc)的不同
pypy的垃圾回收機(jī)制實(shí)現(xiàn)并不是使用引用計(jì)數(shù),所以O(shè)bject并不會在不被引用的情況下立即釋放掉。最明顯的影響是,文件(socket等)將不會在離開作用范圍后立馬被關(guān)閉掉。對于寫打開的文件,這可能會導(dǎo)致寫入的數(shù)據(jù)在緩沖區(qū)中一段時(shí)間,是的磁盤上文本被截?cái)嗷蜻€未寫入。還可能導(dǎo)致文件打開數(shù)量超過系統(tǒng)的限制。
如果需要調(diào)試程序中哪里沒有正確關(guān)閉文件,可以使用-X track-resources
來運(yùn)行程序。這樣,每當(dāng)GC關(guān)閉一個(gè)文件(或者socket)將會產(chǎn)生一個(gè)ResourceWarning
。這個(gè)警告會包含文件(或者socket)打開創(chuàng)建的位置,方便定位問題。
測試代碼:
import time
import gc
print("start")
i = 1
while True:
print(i)
i += 1
open("/data/test.log", "rw")
if (i % 10) == 0:
gc.collect()
print("finished")
對__del__
和弱引用的影響
這個(gè)問題,會影響到__del__
方法調(diào)用的準(zhǔn)確時(shí)間,因?yàn)閜ypy的回收是不確定的。這同樣影響到弱引用(weak references),使得弱引用會比預(yù)期的存活時(shí)間長。這導(dǎo)致弱引用代理(由weakref.proxy(object[, callback])
返回)的實(shí)用性降低:這使得弱引用代理在目標(biāo)對象的引用失效后仍然能夠被訪問,且會在某個(gè)時(shí)刻突然失效并在下次訪問時(shí)引起ReferenceError
錯(cuò)誤。所有使用到弱引用代理的必須小心處理ReferenceError
(或者,更好的方法是使用weakref.ref()
而不是weakref.proxy()
)。
測試代碼:
>>>> import weakref
>>>> import gc
>>>> class A(object):
.... def __init__(self):
.... self.test_attr = 100
....
>>>> def test_func(refrence):
.... print("callback function!")
....
>>>> a = A()
>>>>
>>>> x = weakref.proxy(a, test_func)
>>>> x.test_attr
100
>>>> a.test_attr
100
>>>> del a
>>>>
>>>> x.test_attr
100
>>>> gc.collect()
callback function!
0
>>>> x
<weakproxy at 0x00007f6f19011dc0; dead>
>>>> x.test_attr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ReferenceError: weakly referenced object no longer exists
>>>>
>>>> a = A()
>>>> x = weakref.ref(a, test_func)
>>>> print x
<weakref at 0x00007f6f190631a0; to 'A'>
>>>> b = x()
>>>> b.test_attr
100
>>>> del a
>>>> gc.collect()
0
>>>> x
<weakref at 0x00007f6f190631a0; to 'A'>
>>>> b.test_attr
100
某些情況下,由于CPython的引用計(jì)數(shù),弱引用會在它指向的對象之前或之后立即釋放掉,如果在之后釋放掉,那么回調(diào)函數(shù)將會被調(diào)用。但在pypy類似的情況下,對象和弱引用會被認(rèn)為同時(shí)釋放,回調(diào)將不會被調(diào)用。
GC的其他影響
如果一個(gè)對象有__del__
方法,在pypy中,__del__
被調(diào)用的次數(shù)不會多于1次。但在CPython中,__del__
在對象被“復(fù)活”然后“死亡”,__del__
可能會被調(diào)用多次。(此處有一段不是很懂,詳見Blog[1] [2].)
GC的差異也會間接的影響到其他方面。比如,pypy代碼中的生成器,將會比CPython中更遲的被垃圾回收。這會影響到yield
關(guān)鍵字,如果yield
在try:
或者with:
中,這會有一個(gè)issue 736。
# import gc
def g():
try:
yield 1
finally:
print "finally"
g().next()
# gc.collect()
這段代碼,在pypy中是沒有打印出finally
,在CPython中是有打印的。原因是,在pypy中,finally
只有在對象被垃圾回收機(jī)制回收時(shí)才會打印。如果在最后調(diào)用gc.collect()
,將能夠打印出來。
使用默認(rèn)的GC(minimark
),內(nèi)建函數(shù)id()
將會像CPython中那樣工作。但使用其他GC,id()
返回的數(shù)字,并不是內(nèi)存地址(因?yàn)橐粋€(gè)對象的地址可能會改變),而且太頻繁調(diào)用將會引起性能問題。
如果程序中有很長的鏈表對象,每一個(gè)中都有指向下一個(gè)的引用,并且都有__del__
,這會導(dǎo)致pypy的GC的性能下降。但在其他情況下,pypy的GC性能普遍比CPython好。
__del__
還有另外一個(gè)不同的地方,如果往一個(gè)已經(jīng)存在的類中動態(tài)加入__del__
,它將不會調(diào)用:
>>>> class A(object):
.... pass
....
>>>> A.__del__ = lambda self: None
__main__:1: RuntimeWarning: a __del__ method added to an existing type will not be called
在pypy中,如果你將__del__
動態(tài)綁定給Python的舊式類的對象(對于CPython的新式類也是不工作的),將會得到一個(gè)RuntimeWarning
。修改這個(gè)issuse的方法是,在類中定義__del__
,僅包含pass
(或者其他實(shí)現(xiàn)),再在運(yùn)行時(shí)動態(tài)修改;
CPython會在程序結(jié)束的時(shí)候去自動執(zhí)行gc.collect()
,但pypy并不會。
內(nèi)建類型(types)的子類
官方實(shí)現(xiàn)上,CPython對于內(nèi)建類型的子類的重載方法是否會被隱式調(diào)用沒有確定任何規(guī)則。類似的,這些被重載的方法不會被同一個(gè)對象的其他內(nèi)置方法調(diào)用。例如:一個(gè)在dict
子類中被重載的__getitem__()
將不會被其內(nèi)置函數(shù)get()
調(diào)用。
上述的情況在CPython中和PyPy中都是正確的。不同的是,一個(gè)除self
以外的另一對象的內(nèi)置方法是否會調(diào)用一個(gè)被重載的方法。這通常在CPython中是不會被調(diào)用的,而在PyPy中則會被調(diào)用。例子:
class D(dict):
def __getitem__(self, key):
return "%r from D" % (key,)
class A(object):
pass
a = A()
a.__dict__ = D()
a.foo = "a's own foo"
print a.foo
# CPython => a's own foo
# PyPy => 'foo' from D
glob = D(foo="base item")
loc = {}
exec "print foo" in glob, loc
# CPython => base item
# PyPy => 'foo' from D
在字典(dictionary)中作為key的自定義類的對象
class X(object):
pass
def __evil_eq__(self, other):
print 'hello world'
return False
def evil(y):
d = {X(): 1}
X.__eq__ = __evil_eq__
d[y] # might trigger a call to __eq__?
在CPython中,__evil_eq__
可能會被調(diào)用到,盡管沒有辦法寫出一個(gè)必能重現(xiàn)的例子。這會發(fā)生在y is not x
且 hash(y) == hash(x)
,同時(shí),hash(x)
是在x
插入在一個(gè)字典中的時(shí)候計(jì)算的。如果條件滿足,這個(gè)__evil_eq__
方法將會被調(diào)用。
PyPy使用一個(gè)特殊的策略來優(yōu)化,一個(gè)用戶自定義類的實(shí)例作為Keys在字典當(dāng)中,且這個(gè)自定義類是沒有重載__hash__
,__eq__
,__cmp__
:當(dāng)使用這個(gè)策略的時(shí)候,__eq__
和__cmp__
將不會被調(diào)用,而是通過查找id(identity)。所以在上述代碼的情況下,PyPy將能保證__eq__
不會被調(diào)用。
在其他情況下(比如,有一個(gè)自定義的__hash__
和__eq__
在y
中),PyPy將會和CPython一樣。
原始數(shù)據(jù)類型的對象標(biāo)識,is
和 id
原始數(shù)據(jù)類型的對象標(biāo)識是根據(jù)值來判斷想等,而不是包裝器的標(biāo)識。這意味著對于一個(gè)任意值的整數(shù)(interger)x
來說x + 1 is x + 1
總是返回True
。這個(gè)規(guī)則適合如下的數(shù)據(jù)類型:
int
float
long
complex
-
str
(只對空字符串或單個(gè)字符的字符串有效) -
unicode
(只對空字符串或單個(gè)字符的字符串有效) -
tuple
(只對空元組有效) -
frozenset
(只對空的frozenset有效)
這個(gè)改變需要id()
也要做出相應(yīng)的改變。id()
需要滿足如下情況:x is y <=> id(x) <=> id(y)
。因此上述類型的id()
將返回一個(gè)從參數(shù)計(jì)算而得到的值,因此可以大于sys.maxint
(所以可以是任意長)。
記住,一個(gè)長度大于等于2的字符串,可以相等(==
,equal)卻不一定相同(is
,identical)。類似的,盡管x
包含一個(gè)元組且x == (2,)
,但x is (2,)
不一定返回True
。這個(gè)規(guī)則只適應(yīng)于上述的類型。str
、unicode
、tuple
和frozenset
是在PyPy5.4版本中才適應(yīng)這個(gè)規(guī)則。在5.4之前,盡管x
等于?
或()
,但是if x is "?"
或者 if x is ()
將會返回False
。這個(gè)5.4中的新行為是更為接近CPython,Cpython可以精確的緩存空tuple
或firzenset
和長度小于等于1的字符串或者unicodes(對于字符串和unicodes并不總是會緩存,當(dāng)大部分情況是)。
對于float,“is
”是針對一個(gè)對象的float
“位模式”。所以float('nan') is float('nan')
在PyPy上返回True
,在CPython上返回False
,因?yàn)檫@是兩個(gè)對象。但是0.0 is -0.0
都返回False
,因?yàn)椤拔荒J健辈煌R话愕模?code>float('nan') == float('nan')總是返回False
。當(dāng)在容器中使用時(shí)(在列表項(xiàng)或者集合中),判斷相等采用if x is y or x == y
(不論在Cpython中或PyPy中)。因此,因?yàn)樗械?code>nans在PyPy中是相同的,所以不能在一個(gè)集合中使用多次,不像CPython(Issuse #1974)
其他
-
hash()
方法的隨機(jī)bug在pypy中是忽略的,所以會有以下不同:
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = "1"
>>>hash(a)
-7159617557763069555
>>>exit()
再次運(yùn)行:
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = "1"
>>> hash(a)
461546025534110251
>>> exit()
兩次的hash值是不同的,而在pypy中,兩次的hash值是一樣的:
Python 2.7.3 (2.2.1+dfsg-1ubuntu0.3, Sep 30 2015, 15:18:40)
[PyPy 2.2.1 with GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``pypy is more stable than debian''
>>>> a = "1"
>>>> hash(a)
6272018864
>>>> exit()
Python 2.7.3 (2.2.1+dfsg-1ubuntu0.3, Sep 30 2015, 15:18:40)
[PyPy 2.2.1 with GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``we still have to write software
with a metaspace bubble in it''
>>>> a = "1"
>>>> hash(a)
6272018864
>>>> exit()
- 不能在一個(gè)類型對象中存儲一個(gè)非字符串的key。例子:
class A(object):
locals()[42] = 3
# 在PyPy中是不行的
sys.setrecursionlimit(n)
僅僅是設(shè)置一個(gè)大概的值。這個(gè)通過設(shè)置一個(gè)n * 768
bytes的可用棧空間來實(shí)現(xiàn)的。在Linux上,這個(gè)依賴于編譯器的設(shè)置,默認(rèn)值768KB大約能滿足1400次調(diào)用。因?yàn)閷τ谧值涞膶?shí)現(xiàn)是不同的,每次調(diào)用
__hash__
和__eq__
所獲的準(zhǔn)確數(shù)字并不相同。由于CPython也沒有一個(gè)準(zhǔn)確的保證,所以不要依賴它。對于
__class__
的賦值使用,是基于CPython2.5上的。對于CPython2.6和CPython2.7多個(gè)特性,PyPy仍未支持(如果需要的話,是可以支持的,但在PyPy上需要比CPython2.6/2.7注意更多情況?)。-
__builtins__
的不同:
在python中有一個(gè)內(nèi)建模塊,中有一些常用函數(shù)。而該模塊在Python啟動后、且沒有執(zhí)行程序員所寫的任何代碼前,Python會首先加載該內(nèi)建函數(shù)到內(nèi)存。在pypy和python2.X中,該內(nèi)建模塊是
__builtin__
,在Python3.X中,該內(nèi)建模塊是builtins
。而
__builtins__
則是對于這個(gè)內(nèi)建模塊的引用。無論任何地方要想使用內(nèi)建模塊,都必須在該位置所處的作用域中導(dǎo)入
__builtin__
(builtins
)內(nèi)建模塊;而對于__builtins__
卻不用導(dǎo)入,它在任何模塊都直接可見。在Python2/3中的主模塊
__mian__
中,__builtins__
是對內(nèi)建模塊__builtin__
(builtins
)本身的引用,即__builtins__
完全等價(jià)于__builtin__
(builtins
)。在Python2/3中的非主模塊
__mian__
中,__builtins__
是對內(nèi)建模塊__builtin__.__dict__
(builtins.__dict__
)的引用,此時(shí)__builtins__
的類型是字典。 對于使用無效參數(shù)直接調(diào)用內(nèi)建類型的內(nèi)部“魔法”函數(shù),結(jié)果會有略微的不同。比如:
[].__add__(None)
和(2).__add__(None)
在PyPy上都將返回NotImplemented
;但在CPython 中,只有(2).__add__(None)
會返回NotImplemented
,[].__add__(None)
將引起TypeError
。(當(dāng)然,[] + None
和2 + None
無論在PyPy和CPython中都會引起TypeError
)。這是內(nèi)部實(shí)現(xiàn)引起的差異,因?yàn)镻yPy沒有內(nèi)部的C語言層面的實(shí)現(xiàn)(Slots?)。在CPython中,
[].__add__
是一個(gè)method-wrapper
,而list.__add__
是一個(gè)slot wrapper
。在PyPy中,它們都是一些普通的綁定或未綁定的方法對象。這有時(shí)會使得一些檢查內(nèi)置類型的工具混淆。比如,在標(biāo)準(zhǔn)庫inspect
模塊中有一個(gè)ismethod()
方法,當(dāng)參數(shù)是綁定或未綁定的方法對象,這個(gè)方法將會返回True
,當(dāng)參數(shù)是method-wrapper
或slot wrapper
時(shí),方法返回False
。但PyPy并不能區(qū)分它們,所以ismethod([].__add__) == ismethod(list.__add__) == True
。在CPython,內(nèi)置類型具有各種方式實(shí)現(xiàn)的屬性。根據(jù)方式,如果試圖寫入(或刪除)一個(gè)只讀(或不可刪除)屬性時(shí),將會引起一個(gè)
TypeError
或者AttributeError
。PyPy試圖在一致性和兼容性之間取舍。這意味著一些小地方將不會和CPython引起相同的異常,比如:del (lambda:None).__closure__
。在純Python中,如果寫一個(gè)類
class A(object): def f(self): pass
,且這個(gè)類有一個(gè)沒有重載f()
的子類B
,這樣B.f(x)
仍然會檢查x
是B
的一個(gè)實(shí)例。在CPython中,如果一個(gè)類型是用C語言實(shí)現(xiàn)的,那個(gè)這個(gè)類型將會有不同的規(guī)則。如果A
是采用C語言實(shí)現(xiàn),所有A
的實(shí)例將會被B.f(x)
接受(實(shí)際上,在這個(gè)情況下B.f is A.f
是成立的)。一些代碼可以在CPython上運(yùn)行,但在PyPy上不能:datetime.datetime.strftime(datetime.date.today(), ...)
(datetime.date
是datetime.datetime
的父類)。無論如何,正確修復(fù)這個(gè)方法調(diào)用應(yīng)該:datetime.date.today().strftime(...)
。在PyPy中,新式類中的
__dict__
屬性將會返回一個(gè)普通的dict,而不是像CPython中那樣返回一個(gè)dict的代理。改變dict將會改變類型,反之亦然。對于內(nèi)置對象,PyPy將會返回一個(gè)不可修改的dict(但行為和普通的dict類似)。gc
模塊的一些方法和屬性會和CPython中有一些略微的不同,比如:gc.enable
和gc.disable
有被支持,但并不是啟用或禁用GC,而是啟用或禁用終結(jié)器(finalizers)的執(zhí)行。過去的版本中,PyPy在交互模式中啟動時(shí)打印一段來之
#pypy IRC
的隨機(jī)一行。但在release版本中,這個(gè)行為已經(jīng)被抑制了。但設(shè)置一個(gè)PYPY_IRC_TOPIC
環(huán)境變量將會啟動這個(gè)行為。要注意使用到的軟件包完全禁用這個(gè)功能。PyPy的readline模塊是完全重寫的,它并不是GUN的readline。它添加了多行的支持(詳見
multiline_input()
)。但另一方面parse_and_bind()
的調(diào)用會被忽略(issue #2072)。sys.getsizeof()
總會引起TypeError
。這是因?yàn)榇撕瘮?shù)的內(nèi)存分析器很有可能給出與PyPy實(shí)際上不同的結(jié)果。讓sys.getsizeof()
返回一個(gè)數(shù)字(需要足夠的工作)是可行的,但是這個(gè)數(shù)字有可能不能準(zhǔn)確代表著這個(gè)對象使用的內(nèi)存大小。在于系統(tǒng)其余部分(?)隔絕的情況下,這個(gè)數(shù)字甚至反應(yīng)不了一個(gè)對象使用的內(nèi)存大小。比如一個(gè)實(shí)例有maps,這個(gè)maps會經(jīng)常在許多實(shí)例之間共享。在這種情況下,這個(gè)maps會被sys.getsizeof()
的實(shí)現(xiàn)忽略,但在某些情況下,如果這個(gè)maps有著很多唯一的實(shí)例,那么它的內(nèi)存開銷是很重要的。相反的,即使是不同的對象,相等的字符串可以共享它們的內(nèi)部數(shù)據(jù),或者一些空的container會一直共享它們部分的內(nèi)存,直到它們不再為空。更奇怪的是,一些list會在你對它進(jìn)行讀操作時(shí)創(chuàng)建一些對象;如果嘗試估計(jì)range(10**6)
的內(nèi)存大小綜合,這個(gè)操作自身會創(chuàng)建一百萬個(gè)整型對象,但這些對象在開始時(shí)不存在的。在CPython中也會有類似的問題,只是少一些。以上就是不實(shí)現(xiàn)sys.getsizeof()
的原因。timeit
模塊在PyPy中的表現(xiàn)會有所不同:它但打印的時(shí)平均時(shí)間和標(biāo)準(zhǔn)差,而不是CPython中的最小值,因?yàn)樽钚≈低ǔJ怯姓`差的。sysconfig
模塊中的get_config_vars
方法和distutil.sysconfig
這兩個(gè)是未完成的。在POSIX平臺,CPython在Makefile中獲取配置變量來編譯生成解析器。PyPy也需要在編譯的期間生成這些值,但還未完成。在
"%d" % d
、"%x" % x
等類似的結(jié)構(gòu)中,當(dāng)x
是一個(gè)long
的子類的實(shí)例時(shí),并且這個(gè)子類重載了__str__
或__hex__
或__oct__
這幾個(gè)特殊方法時(shí):PyPy將不會調(diào)用這些特殊方法;CPython是會的,但僅限于long
的子類,不包括int
。CPython的這些表現(xiàn)是很混亂的:比如,對于%x
應(yīng)該調(diào)用__hex__()
,__hex__()
的功能是支持返回一個(gè)類似-0x123L
的字符串了;然后%x
會去掉0x
和最后的L
,保留其余部分。如果重載的__hex__()
返回一個(gè)格式不正確的字符串,那么將會獲得一個(gè)異常(在CPython2.7.13之前會之前crash)。在CPython2.7.13中,
sqlite
模塊有一個(gè)更新,當(dāng)有一個(gè)提交時(shí)它將不再重置所有的游標(biāo)(cursors)。這會使得PyPy中有一些麻煩(CPython也可能會有),所以PyPy并沒有移植這個(gè)更改:http://bugs.python.org/issue29006。