Differences between IronPython 1.0.x and CPython 2.4.3
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.
- Overview.........................................................................................................................................
- Standard Types, Functions, and Behaviors...........................................................................
- Regular Expressions....................................................................................................................
- Extension Modules.......................................................................................................................
- Interpreter and Environment.....................................................................................................
- Garbage Collection.......................................................................................................................
Overview
CPython (the standard for Python) and IronPython are two different implementations of the Python language. While a
Language Referenceexists 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
http://www.codeplex.com/ironpythonso 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.
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 reduceex
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.funccode.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 replaceerror/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
http://www.codeplex.com/WorkItem/View.aspx?ProjectName=IronPython&WorkItemId=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
http://www.codeplex.com/WorkItem/View.aspx?ProjectName=IronPython&WorkItemId=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 |
| >>> x | >>> x |
| 1.234 | 1.234 |
| >>> print x | print x |
| 1,234 | 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=5 |
| >>> i is 5 | >>> i is 5 |
| False | True |
| >>> i=5000 | >>> i=5000 |
| >>> i is 5000 | >>> i is 5000 |
| False | False |
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
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
- codecshk
- audioop
- _multibytecodec
- parser
- array
- msvcrt
- codecskr
- sha
- strop
- _heapq
- codecsjp
- imageop
- mmap
- _subprocess
- codecstw
- regex
- zipimport
- cmath
- _winreg
- xxsubtype
- codecscn
- md5
- codecsiso2022
- rgbimg
- _csv
- signal (.NET does not support signals)
- _hotshot
- _symtable
The sys module does exist though it is not listed in sys.builtin
modulenames.
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.a2bbase64(‘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.
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
modulenames 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.
- apiversion - This always has the value: "IronPython does not support the C APIs, the apiversion 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.
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.