S
Steven D'Aprano
--> int="five"
--> [int(i) for i in ["1","2","3"]]
TypeError: str is not callable
Now how are you going to get the original int type back?
Trivially easy:
py> int
<type 'int'>
py> int = "five" # Oops!
py> int(42.5)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'str' object is not callable
py> del int
py> int(42.5) # Phew!
42
Thank you for bringing this back up. Was it you who suggested that
built-in are re-assignable?
It's not just a suggestion, it is a fact. The built-ins are just a
namespace, like any other module, class, or other namespace.
(Of course, if you break something in the built-ins, the consequences are
likely to be significantly more wide-ranging, but that's another issue.)
However, in the code shown above, you don't actually reassign a built-in.
You merely shadow it within the current module. Do you understand the
difference? In the above, the *builtin* int still exists, but your code
can no longer get direct access to it because a *global* int gets in the
way. Using Python 2.7:
py> import __builtin__ as builtins
py> builtins.int
<type 'int'>
py> int = "five"
py> int
'five'
py> builtins.int
<type 'int'>
so deleting the global "int" simply reveals the otherwise hidden
builtin.int instead.
However, if you rebind the builtin, Python doesn't remember what the old
value was (although in principle it could):
py> del int # get rid of the global
py> int is builtins.int
True
py> builtins.int = "six" # oh oh, this could be bad
py> int
'six'
py> del int
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'int' is not defined
In this case, deleting the builtin doesn't magically recover it, it just
deletes it:
py> del builtins.int
py> int
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'int' is not defined
At this point, in general, you've buggered up the current Python
environment and would normally need to restart the interpreter. But in
this specific case, all is not quite so lost: we can recover from this if
only we can find another reference to the int built-in type, and restore
it to the builtins:
py> builtins.int = type(42)
py> int("23")
23
I see no reason why Python couldn't create a read-only "backup builtins"
namespace, but on the other hand, why bother?
Because this is a bad idea for the reasons I just showed.
"Breaking things" is always a bad idea. But re-binding is not necessarily
a bad thing. Let's say I want to find out how often the built-in "len"
function is called by some module:
py> count = 0
py> def mylen(x):
.... global count
.... count += 1
.... return _len(x)
....
py> _len = len # save the real len
py> builtins.len = mylen # monkey-patch the builtins
py> import mymodule
py> count
3
Now obviously this is a trivial example. But there are more interesting,
and useful, reasons for monkey-patching builtins, usually for testing and
debugging purposes. Such a technique should be used with caution, but it
can be used.