Differences between IronPython and CPython

 

Information in this document is subject to change without notice. The example companies, organizations, products, people, and events depicted herein are fictitious. No association with any real company, organization, product, person or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarked, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

© Microsoft Corporation. All rights reserved.

Microsoft, MS-DOS, MS, Windows, Windows NT, MSDN, Active Directory, BizTalk, SQL Server, SharePoint, Outlook, PowerPoint, FrontPage, Visual Basic, Visual C++, Visual J++, Visual InterDev, Visual SourceSafe, Visual C#, Visual J#,  and Visual Studio are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries.

Other product and company names herein may be the trademarks of their respective owners.

 

 

1     Overview........................................................................................................................ 2

2     Standard Types, Functions, and Behaviors....................................................................... 2

3     Regular Expressions........................................................................................................ 6

4     Extension Modules.......................................................................................................... 6

5     Interpreter and Environment........................................................................................... 7

6     Garbage Collection.......................................................................................................... 8

 

 

 

 

 

1        Overview

CPython (the standard for Python) and IronPython are two different implementations of the Python language.  While a Language Reference exists for the Python language, there are a number of features of the language that are incompletely specified.  The following lists all known differences between the two implementations of the Python language.  These differences range from the trivial (such as, IronPython has different error messages in some cases, but raises the same exception type) to the significant (such as, IronPython does not implement some standard extension modules like cmath).

Any other differences not listed here are purely accidental omissions.  Please submit a bug report at www.codeplex.com/ironpython so that we can either fix the difference or update this document until we can fix it.

The IronPython team is very concerned about compatibility with CPython, and we plan to fix all incompatibilities that are not acceptable.  Some incompatibilities (for example, those due to garbage collection implementation) are officially acceptable.  We determined this by discussing these issues with the Python community.  In some other cases, the CPython test suite needs to be updated where it makes inappropriate assumptions about implementation characteristics.

This list has been updated to describe the differences between IronPython 1.0 and CPython 2.4.3.

2        Standard Types, Functions, and Behaviors

IronPython sometimes displays different error messages for SyntaxError exceptions. The raised exception type (SyntaxError) is the same as in CPython.

IronPython has slightly different error messages when parsing arguments to eval().  IronPython identifies the file name as "<string>", but CPython does not report anything as a file name or that the error was found while parsing a string.

IronPython allows __slots__ to be defined on subclasses of tuple (for example, “class foo(tuple): __slots__ = ‘abc’”).  CPython does not allow this and instead raises a TypeError stating non-empty slots are not supported on subtypes of tuple.

IronPython cannot call __reduce__ or __reduce_ex_ on None.  IronPython mistakenly believes it does not have an instance and therefore disallows calls of __reduce__ and __reduce_ex__ on None.  For __reduce__ both implementations raise a TypeError but for different reasons.  For __reduce_ex__ IronPython throws an exception, but CPython can successfully reduce the None object.

When dir is used on instances of a type that has a metaclass, the resulting list has some missing attributes.  By default CPython defines __delattr__, __getattribute__, __hash__, __setattr__, and __str__.  IronPython  does not display these in dir()’s results but they are callable.

Tracebacks display carets indicating the column for syntax errors where there are invalid assignments (for example, “def f(x): [x for x in x] = x”).  CPython does not do this.  Reproducing this behavior requires that you use the CPython standard library for displaying tracebacks.

When getting a method from a class that has not been instantiated, IronPython returns an unbound method while CPython returns a function.

class C(object):

    def foo(self): pass

print C.__getattribute__(C, 'foo')

 

IronPython allows calling __setattr__ on types.  CPython disallows this and raises a type error, stating that you can’t apply __setattr__ to a type object:

class foo(object): pass

foo.__setattr__(foo, ‘__str__’, ‘bar’)

 

IronPython modules have a __dict__ attribute that contains the dictionary for the module.  In IronPython “dir(__dict__)” displays the usual attributes for a dictionary, but CPython raises a NameError because __dict__ is not defined.

IronPython catches string exceptions by value, but CPython catches string exceptions by reference.  For example, IronPython will catch this exception, but CPython won’t:

                try: raise 'abc'

except 'a' + 'bc': pass

 

When accessing a file with universal new line support, IronPython and CPython can return different sizes for the file after reading partial strings.

IronPython and CPython display different error messages when calling a user type that does not take any parameters, but they do raise the same exception type.

The sys.version value is different between the two implementations.

The maximum recursion limit in IronPython is unlimited by default, and you can call sys.setrecursionlimit() to set it to the maximum stack height.

IronPython is more lenient regarding the use of keyword arguments in many circumstances.  For example, “[].append.__call__(item=’abc’)” works in IronPython but raises an exception in CPython.  Regarding _weakref, IronPython allows using keyword arguments on the weakproxy method wrappers.  IronPython is also less restrictive for some string methods.  For example, the following works in IronPython but raises an error in CPython:

x = ""

x.center(1, fillchar='*')

 

IronPython has a different type hierarchy than CPython for representing system types.  IronPython uses a single base class with distinct subtypes for built-in and user types.  If programmers try to test whether an object is a type object by using Python's identity operator (is), instead of using instanceof(), then they may get different results.

IronPython allows setting attributes on built-in functions.

IronPython does not allow you to set attributes on __builtins__, but CPython does let you do this.

IronPython allows you to set the value of __builtins__, as does CPython, but the results are different.  For example, import will no longer work in IronPython, but the built-in function min() will continue to work.

IronPython reports the value of __builtins__ to be a type, but CPython reports it to be a module.

IronPython does not include local variables in co_varnames.  For example, "foo.func_code.co-varnames" for "def foo (x, y): z = 10" only returns 'x' and 'y'.

IronPython raises a ValueError for very large exponents (for example, 10 ** 735293857239475) while CPython hangs trying to compute the number.  We probably won't fix this one.

IronPython's compile() function behaves differently than CPython's compile() function in some cases.  CPython's compile function raises a SyntaxError for some trailing whitespace, but it does not do this when compiling a file.  For example, the "x = compile('def f(a):\n\treturn a\n\t', '', 'single')" trailing \t causes an error in this case.  We do not intend to fix this difference.

IronPython uses unicode characters and strings, not ASCII as CPython does.  For example "'%c' % i" for 255 < i <65536 raises an error in CPython but succeeds in IronPython.  We may wait to see how Python3k incorporates unicode before fixing this issue.

IronPython will compile files whose identifiers use non-ASCII characters if the file has an encoding comment such as "# -*- coding: utf-8 -*-".  CPython will not compile such a file in any case.

IronPython does not support a DeprecationWarning mechanism.

IronPython does not support a -W switch to control warnings.

IronPython has slightly different system-defined attribute names on some types.  For example, try "dir(True)" in both CPython and IronPython.

Setting sys.std* attributes does not affect IronPython’s console behavior.

If executing within the dynamic context of a generator, and an exception is raised, IronPython exhibits a different behavior than CPython.  IronPython will continually re-raise the same exception every time you call next() on the generator.  CPython raises a StopIteration exception on subsequent calls to next().

IronPython does not handle falling off the end of generator functions the same way as CPython.  When you call next() after a last yield statement has executed, IronPython continually returns execution to the point immediately after that yield statement, executes to the end of the function, and then raises a StopIteration exception.  CPython executes from the last yield to the end of the function only one time, and then subsequent calls to next() immediately raise a StopIteration exception.

IronPython does not allow yield statements in nested try blocks.

IronPython raises an exception when it cannot convert a string to a unicode string, and CPython just returns the argument to unicode().

IronPython's _codecs module implementation is incomplete.  There are several replace_error/lookup_error handlers that IronPython does not implement.

IronPython does not implement type.mro, and user overrides do not affect how a type's __mro__ works.  In CPython you can override a type’s mro method to alter the method resolution order, but IronPython raises an exception if you try to set type.mro.  Calling mro on any type raises an exception, but __mro__ still works on types.

IronPython does not support overriding __getattribute__ for some user-defined subclasses of built-in types.

When printing expression results in the console, IronPython calls __str__ on new style classes while CPython calls __repr__.

IronPython gives different error messages and raises different exceptions in some situations using the complex built-in function.  For example, calling complex on an old style class instance in CPython raises an AttributeError due to no __float__ function existing, but IronPython raises a TypeError.  Doing the same thing on a new style class raises a TypeError in both implementations, but CPython's message explains the argument must be a string or number while IronPython's message just says it cannot convert to complex.

IronPython raises different exceptions than CPython (and sometimes raises exceptions when CPython does not) in isinstance() with complex class definitions that affect bases and return bases in various ways.  See CodePlex bug 2169 for details.

IronPython’s behavior differs from CPython’s behavior if you call del on __builtin__.pow and then try to print the value of pow within a module.  Importing or executing the module from the command line in IronPython will print "<built-in function pow>" while CPython raises a NameError.

IronPython has extra attributes ('msg' and 'clsException') on exception objects.

IronPython does not return a code object if it encounters a syntax warning when calling compile().  IronPython raises a SyntaxWarning exception, but CPython catches and prints the exeption before returning a code object.

IronPython does not invoke the __setattr_ attributes for old style classes when setting an attribute.   See CodePlex bug 2295 for more info.

IronPython supports fromkeys() on some dictionaries for which CPython does not provide fromkeys() support.  For example, “file.__dict__.fromkeys” returns a method in IronPython and raises a TypeError in CPython.

IronPython allows you to set a key of value 2 in class’s __dict__, but CPython does not.  CPython only allows you to do this with the __dict__ of a class instance, not the class itself.  Try “C.__dict__[2]  = ‘2’”.

IronPython supports __slots__ for subtypes of type, but CPython does not.  For example, the following works in IronPython:

class foo(type):

__slots__ = [“abc”]

 

IronPython doesn’t support supplying named values for format string directives  if the name has parentheses in it, for example, “%((foo))s” % {‘(foo)’ : ‘fooval’ }.

When formatting float numbers, IronPython doesn’t raise an Overflow exception for formatting with too high a precision (for example, >=67).

IronPython doesn’t support overriding __getattribute__ on built-in objects.

IronPython cannot create weakref proxies that reference deque and set objects.

IronPython supports ‘continue’ statements in ‘finally’ clauses.

IronPython’s built-in function reversed() behaves slightly differently than CPython’s reversed() function.  For example, calling len() on the result of “reversed(xrange(5))”  raises a TypeError.  Also, calling len() on the result of calling reversed() on custom iterators (for example, a class that supports __getitem__ and __len__) fails.  This behavior happens because the reversed() iterator doesn’t provide access to the original __len__ implementation.

IronPython’s implementation of buffer doesn’t support binary operations between buffers and strings (for example, concatenation with a buffer and string).

IronPython does not call __len__ on old style classes when slicing.  This results in the end index potentially being negative in IronPython.  CPython adjusts to the appropriate end index, but it raises an AttributeError if the old style class does not have a __len__ attribute.

IronPython does not allow opening partitions and drives for read as binary files, but CPython does allow this.  For example, IronPython detects the “\\.\” idiom in “f = file(r'\\.\PhysicalDrive', 'rb')” and raises a ValueError since .NET does not support this functionality.

IronPython’s built-in apply function has a bug in that it requires at least two arguments.

Printing numbers on a machine with French locales produces different output:

IronPython

CPython

>>> x = 1.234

>>> x

1.234

>>> print x

1,234

>>> x = 1.234

>>> x

1.234

>>> print x

1.234

 

Small integer caching in IronPython is different than in standard CPython.  If you set i = 2  and then test "i is 2", the code produces different results in IronPython and CPython.  However, the consistency of the result of such expressions is not guaranteed even within CPython, which seems to be using different small integer caching strategies for different situations:

IronPython

CPython

>>> i=5

>>> i is 5

False

>>> i=5000

>>> i is 5000

False

>>> i = 5

>>> i is 5

True

>>> i = 5000

>>> i is 5000

False

 

3        Regular Expressions

IronPython returns a regular expression match when your pattern matches the beginning of a string, but you supplied a start index past the start of the string.  In this same case CPython returns None.

IronPython raises a more specific exception (IndexError instead of sre_constants.error) when using an invalid group reference in regular expressions with named groups -- for example, “re.sub(r'(?P<id>b)', '\g<1>\g<30>blah', 'bb')”.

Since the IronPython regular expression implementation uses the .NET Framework regular expressions implementation, IronPython supports some syntax not supported by CPython (note, CPython has a similar syntax for affecting the entire pattern, but it is different than these mechanisms in syntax and scope of effect):

·         (?i:foo)  -- ignore case

·         (?m:foo) -- multi-line mode (^ and $ match at the beginning and end, respectively, of any line, not just beginning and end of the whole string)

·         (?s:foo) -- single line mode (period “.” matches every character instead of every character except \n)

·         (?x:foo  bar) -- ignore whitespace in the pattern

4        Extension Modules

IronPython support importing .NET Frameworks assemblies as extension modules.  Usually you need to import the built-in extension module clr and then call one of the clr.AddReference... functions.

Some CPython built-in extension modules do not exist in IronPython:

_bisect

_codecs_hk

audioop

_multibytecodec

parser

array

msvcrt

_codecs_kr

_heapq

_codecs_jp

imageop

mmap

_subprocess

_codecs_tw

regex

 

zipimport

xxsubtype

_codecs_cn

md5

_codecs_iso2022

rgbimg

_csv

signal

_hotshot

sha

cmath

_symtable

_winreg

strop

 

The sys module does exist though it is not listed in sys.builtin_module_names.

IronPython has these additional modules: 're', 'copy_reg', 'socket'.  These are built in rather than being implemented in Python either to leverage the .NET Frameworks or to avoid dependencies on CPython for a minimal installation.

Passing malformed data to binascii.a2b_base64 results in different error messages.  IronPython will raise a TypeError in this situation, and CPython will raise a binascii.Error.  For example try executing “binascii.a2b_base64(‘A’)”.

IronPython’s pickle module doesn’t support fast mode.

The pickle implementation in IronPython doesn’t doesn’t handle all cases of pickling deque objects (recursive deque for example) and sets.

The doctest module does not run in IronPython.

IronPython doesn’t support the select module.

IronPython doesn’t support the _testcapi module.

IronPython doesn’t implement socket.getservbyname() because IronPython uses .NET base class libraries to implement the socket module, and they don’t provide the support for that function.

IronPython doesn’t support the makefile method on socket objects.

IronPython does not have an xxsubtypes built-in module.

IronPython has no os.system function.

5        Interpreter and Environment

IronPython does not by default have the standard CPython libs on its path (for example, .  You can fix this by adding these two lines to the site.py file in the IronPython lib directory:

import sys

sys.path.append(r"c:\python24\lib")

 

IronPython does not redirect the interpreter's error output in response to setting sys.stderr.

IronPython has different command line editing support than CPython.

IronPython supports different command line options than CPython supports.  Invoke ipy.exe with the "-?" switch to see options.

IronPython's sys.builtin_module_names tuple contains different values than CPython's result.  See section Extension Modules for differences.

IronPython has several incompatibilities relating to the interpreter and the sys module’s hooks:

·         settrace

Calling this raises a NotImplementedException.

·         api_version

This always has the value: "IronPython does not support the C APIs, the api_version is not supported".

·         displayhook

Setting this will throw a NotImplementedException.

·         _getframe

Calling this function raises a ValueError exception.

·         __excepthook__

IronPython does not support __excepthook because it does not implement sys.excepthook().  IronPython does not currently support replacing function definitions in the sys module.  Note, excepthook is an attribute in the sys module, but it is bound to a string: "IronPython does not support sys.excepthook".

·         setcheckinterval

IronPython does not use the value set with this function.

IronPython allows access to __dict__, __module__, __class__, and __init__ at the global level, but CPython does not.

Python prohibits using identifiers before the occurrence of global statement if the global statement includes the identifier.  In these cases, CPython reports a syntax warning while IronPython raises a SyntaxWarning exception. For example:

def f():

    a = 1

    global a

 

The sys._getframe() function is not supported by IronPython.  In addition, the semantic of deleting the sys._getframe is different than CPython’s.  In IronPython, once sys._getframe is deleted, it is not possible to store a value to sys._getframe.

6        Garbage Collection

IronPython has a more modern GC whereas CPython uses reference counting, and IronPython's GC choice is considered to be a valid and acceptable implementation.  This has several effects which are listed below.

IronPython users don't need to worry about handling circular references as these are guaranteed to be collected properly.  This behavior is acceptable.

IronPython does not have guarantees for when finalization or system resource freeing occurs.  This can cause problems for people who use open("foo", 'r').read() excessively.  This behavior is acceptable.

IronPython does not immediately invoke __del__ methods when del is called on a variable; it happens during the next GC pass.  Similarly, using del on an object that a weakref object refers to and then immediately testing if the weakref is None may return False.  This behavior is acceptable.

Calling sys.getrefcount raises a NotImplementedError.  Alternatively IronPython could always return some positive constant since there's a reference that was passed to getrefcount.

In CPython you can observe the re-use of some tuple objects in some situations, but this is an implementation detail that no one should depend on.  In IronPython there is no such re-use.