Why no warnings when re-assigning builtin names?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Wed Aug 17 04:15:19 EDT 2011


On Wed, 17 Aug 2011 01:17 pm Seebs wrote:

[...]
> "Another" scope is normally a horizontal thing -- you're talking about
> a different scope such that you are *either* in this one *or* in that
> one.
> 
> Built-ins are not in a scope you are never not in.

That's technically incorrect. Built-ins are a scope you are never in, if
by "in" you mean "code is executed in this scope".

You have three scopes in general:

Local
Global
Built-ins

(There's also zero or more nonlocal scopes, between local and global, that
applies to closures and nested functions, but never mind that.)

Code is almost(?) always executed in the local scope. (eval and exec let you
mess around with that, somewhat.) E.g. an assignment "x = 1" applies to the
local namespace unless you explicitly declare it global. If you are in the
top level of a module, the local namespace is also the global one, the
global statement does nothing, and the assignment occurs in the global
namespace.

However, name lookup rules are such that while assignments are always local,
unsuccessful lookups may fall through to global then built-in. 

See also: http://www.python.org/dev/peps/pep-0227/

The only way to put something into the built-in namespace is by using the
fully-qualified name:

>>> import builtins  # Use __builtin__ in Python 2
>>> builtins.x = 1  # Kids! Don't try this at home!
>>>
>>> x
1
>>> del x  # prove it isn't a global or local
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

So a top-level (global) assignment, say:

def sum(list):
    ...

*shadows* the built-ins sum and list, it doesn't replace them. It defines a
local variable "list" and a global variable "sum", but it doesn't touch
either built-in. They are still available via the fully qualified name
builtins.sum and builtins.list.


[...]
>> (4) And then, after a while, you decide that perhaps shadowing is not
>> always so bad. (It helps if the Effbot tells you off for objecting to
>> shadowing in a two-line function.) At first, you limit yourself to using
>> parameter names that shadow built-ins in small tool-like functions. Then
>> when the world doesn't implode, you rethink the use of top-level function
>> names like "izip" and realise that namespaces exist so that you don't
>> need to care about shadowing functions you don't use, and if people call
>> import * they have nobody to blame but themselves if things break.
> 
> Hmm.  See, I've never reached that, in Python or any other language.  I
> figure it creates a new potential for confusion, and that I would rather
> avoid any ambiguity.  I don't *like* ambiguity in code.

Ah, well you see the thing is, this is Python. As soon as you call any
function you don't control, you no longer know what your environment is
with any certainty. For all you know, the harmless-looking function is
monkey-patching builtins like there's no tomorrow. Speaking broadly,
perhaps too broadly, we're incredibly proud of the ability to modify nearly
everything at runtime.

Fortunately, while we are proud of having that ability, actually *using* it
is considered a mortal sin. We're not Ruby developers -- if you actually
monkey-patch something, especially built-ins, you can expect to be taken
outside and slapped around with a fish if you get caught.

http://www.youtube.com/watch?v=IhJQp-q1Y1s

 
> So I don't shadow stuff that's part of the language, because doing that
> makes it possible for a line of code to have a clear and obvious meaning
> to someone who looks at that line out of context, and a *completely
> different* clear and obvious meaning to someone who looks at it with a bit
> more
> context.  I don't like that!  It means that someone reading my code can
> never, ever, assume that a standard language feature is actually itself
> and not a local shadow which does something different unless they go
> walking back up the scope chain checking.  And that's a pretty big cost
> to attach to stuff that is, by design, basic and universally available.

Sure. But they can't have that certainty regardless of whether you shadow
something, because how do they know whether you've shadowed it or not?

In theory, anything could be anything at any time, and you have no
protection. In practice, I worry more about being eaten by
genetically-engineered flying piranhas than about rogue monkey-patching
code.


-- 
Steven




More information about the Python-list mailing list