abusing __builtins__

Thomas Wouters thomas at xs4all.net
Mon Feb 26 01:53:22 EST 2001


On Mon, Feb 26, 2001 at 07:50:35AM +0200, Vassilis Virvilis wrote:

> > The language may someday make "GlobalVariable" the name of its own builtin,
> > and then your code won't work correctly if you either try to use the new
> > builtin or call any other module that does (incl. without limitation std
> > library modules).

> This I don't get it. Why is that? GlobalVariable is just a name to
> indicate the purpose of my variable. If a newer version of python use it
> in a later stage as a reversed word (__builtins__ variable or function),
> then obviously my old program won't be able to use the new functionality
> but it will overwrite it happily. So it would work even then.

First off, entries in builtin aren't "reserved words" as such. This is quite
a subtle difference, but an important one none the less. Reserved words are
very limited in Python, and I believe none were added since Python 1.0, when
'lambda' was put in at the very last moment. In fact, in Python 1.4, a
formerly reserved word ('access') was removed ! :) Reserved words are
reserved specifically for statements and special syntax. Reserved words are
part of the grammar of the language, and can't be used as variable names or
(in CPython) other places that need a name (like def, class, attribute
setting/getting, etc.) This is why (in CPython) you can't even have a method
called 'print', 'def' or 'class'. (If you want to know why: it's a flaw in
the parser/tokenizer. Feel free to fix it and submit a patch!)

Builtin functions and variables are a different story, however. They are
just conveniency names, are searched as a 'last resort', and are perfectly
permissible as variable names wherever you want them. If you use a name that
is defined in the builtins namespace as a local or global variable, nothing
weird happens. You lose access to the builtin from that function or module
(respectively), but since you wrote the code yourself, you are probably not
using it anyway. Other functions and modules don't notice or care that
you're shadowing the builtin function in your function or module.

(The masking of globals is one of the reasons why 'from module import *' is
generally a bad idea even on the module level.)

But if you add an entry into builtins, and later a builtin of that name gets
added, you will replace the builtin function with your own, probably
completely different function. All functions and modules will notice this.
And whenever your code, which expects 'GlobalVariable' to be your specific
function/variable, imports/execs code that expects 'GlobalVariable' to be
the new builtin funtion, you end up with weird errors (at best) or very
weird behaviour (if your code doesn't throw an exception.)

And especially the standard library has a very good chance to already be
using the new 'GlobalVariable' builtin function, since it's released at the
same time as the source, and is expected to work only with the Python
version it's released with. 

> Consider the following imaginary example. In a project where there is no
> need to open files one replaces the open function. So this project will
> never manage to open a file but aside from that it will continue to work
> as designed.

This is a different situation entirely! As long as you provide the same
interface for the function you are replacing, and *intend* for it to replace
the normal 'open' call, there is no problem. You might run into a problem in
the future, though, when builtins becomes unwritable. (Which, for all we
know, might happen in Python 2.3 -- but not without warnings first <wink> :)

If you really want this, though, you should consider using something like
Bastion: run your code in a shielded environment with some builtins/modules
removed or wrapped in protective functions.

Readability-is-still-the-best-argument-ly y'rs,
-- 
Thomas Wouters <thomas at xs4all.net>

Hi! I'm a .signature virus! copy me into your .signature file to help me spread!




More information about the Python-list mailing list