CPython Compatibility#
This runtime intends to be a drop-in replacement for CPython. Occasionally, it is advantageous for performance to deviate in small ways. These deviations should not affect the majority of programs and it should be easy to adapt the rest.
This document describes the differences. Note that it does not cover features that are planned but not implemented yet.
Built-in Types#
-
module.__dict__is always a dictionary and initialized inmodule.__new__; CPython initializes it withNoneand only sets it to a dictionary inmodule.__init__. -
Type dictionaries must only have
strkeys that do not override__eq__or__hash__. This Example will raise aTypeError:
>>> class A:
... locals()[500] = 1
...
TypeError: '_type_init' for 'str' objects doesn't apply to a 'int' object
-
Object attributes must only have
strnames that do not override__eq__or__hash__. Identities of attribute names may not preserved. -
str.__add__with a non-str other returnsNotImplementedin Skybison but raises aTypeErrorin CPython. This is because CPython splits the slots into competingnb_addandsq_concatslots that don't exist here. PyPy does something similar to Skybison.
Interpreter#
-
Changing
__builtins__has an immediate effect, as opposed to CPython which caches the value and only updates the cache when calling across module boundaries. We generally do not recommend to reassign__builtins__and may further limit the ability to do so in the future. -
A dictionary passed to the
globalsparameter ofbuiltins.exec,builtins.eval,PyEval_EvalCodeis not updated while the code is being executed, but will be updated only upon completion of the call. Note that this does not affect passing<some_module>.__dict__for globals;__dict__of a module returns a specialized proxy object which leads to module attributes being updated immediately as the code is running. -
Similarly, a dictionary passed to the
globalsparameter of the function constructor (types.FunctionType), will have its contents copied to a specialized proxy object inside a module. This means that any changes to globals from within the function will not reflect in the dictionary passed-in, but instead in the function's module proxy object. The following test will fail:def _f(): global foo foo = "baz" d = {"foo": "bar"} result = types.FunctionType(_f.__code__, d, name="hi") self.assertEqual(d["foo"], "baz")
C-API#
-
PyCFunction_TypeandPyCFunction_Checkare not supported;PyCFunction_Newworks and returns something that behaves similar. -
PyEval_EvalCode: Seebuiltins.exec.
Runtime Inspection#
sys._getframe()always returns a new object whereas CPython returns an identical object for the same frame:
>>> sys._getframe(0) is sys._getframe(0)
False