Python: ¿Cuál es la diferencia entre __builtin__ y __builtins__?

Estaba codificando hoy y noté algo. Si abro una nueva sesión de intérprete (IDLE) y compruebo lo que está definido con la función dir , obtengo esto:

 $ python >>> dir() ['__builtins__', '__doc__', '__name__', '__package__'] >>> dir(__builtins__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'] >>> import __builtin__ ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'] >>> dir(__builtin__) == dir(__builtins__) # They seem to have the same things True 

Por favor, tenga en cuenta la última línea.

Entonces, mi pregunta es:

Importante:

Estoy usando Python 2.7.2+ en Ubuntu.

Directamente de la documentación de Python: http://docs.python.org/reference/executionmodel.html

De forma predeterminada, cuando se encuentra en el módulo __main__ , __builtins__ es el módulo __builtin__ (nota: no ‘s’); cuando se encuentra en cualquier otro módulo, __builtins__ es un alias para el diccionario del __builtin__ módulo __builtin__ .

__builtins__ se puede configurar en un diccionario creado por el usuario para crear una forma débil de ejecución restringida.

Detalle de la implementación de CPython: Los usuarios no deben tocar __builtins__ ; Es estrictamente un detalle de implementación. Los usuarios que deseen anular los valores en el espacio de nombres integrado deben import el __builtin__ (no ‘s’) y modificar sus atributos de manera apropiada. El espacio de nombres para un módulo se crea automáticamente la primera vez que se importa un módulo.

Tenga en cuenta que en Python3, el módulo __builtin__ ha sido renombrado a builtins para evitar algo de esta confusión.

Debe usar __builtin__ en sus progtwigs (en los casos raros que lo necesite), porque __builtins__ es un detalle de implementación de CPython. Puede ser idéntico a __builtin__ , o a __builtin__.__dict__ , dependiendo del contexto. Como dice la documentación :

La mayoría de los módulos tienen el nombre __builtins__ (tenga en cuenta las ‘s’) disponible como parte de sus globales. El valor de __builtins__ normalmente es este módulo o el valor del atributo __dict__ de este módulo. Dado que este es un detalle de implementación, no puede ser usado por implementaciones alternativas de Python.

En Python 3, __builtin__ ha sido renombrado a builtins , y __builtins__ sigue siendo el mismo (por lo que solo debe usar builtins en Python 3).

Guido quería unir a __builtin__ y __builtins__ , como pueden ver aquí (“Tener a __builtins__ y __builtin__ es claramente una mala idea”), pero aparentemente no surgió nada.

Aparentemente, el uso de __builtins__ es para el rendimiento: brinda acceso directo a __builtin__.__dict__ cuando se usa en un módulo no principal, y por lo tanto elimina un nivel de __builtin__.__dict__ indirecto.

__builtin__ es un módulo que contiene las funciones y tipos incorporados. El hecho de que un nombre __builtins__ esté disponible con las mismas cosas es un detalle de la implementación. En otras palabras, si necesita usar uno de ellos, import __builtin__ y luego use __builtin__ . Consulte la documentación .

Puedes entender esto como el siguiente código. cuando se inicia cpython, cpython carga __builtin__ módulos en el espacio de nombres global

importar __builtin__ como __builtins__