Why no warnings when re-assigning builtin names?

Seebs usenet-nospam at seebs.net
Tue Aug 16 23:17:23 EDT 2011

On 2011-08-17, Steven D'Aprano <steve+comp.lang.python at pearwood.info> wrote:
> Seebs wrote:
>> On 2011-08-16, Steven D'Aprano <steve+comp.lang.python at pearwood.info>
>> wrote:
>>> *My* objects certainly are, because I write documentation for my code. My
>>> docs are no less official than Python's docs.

>> Sure they are.  I can't get yours from python.org.

> And what makes that unofficial? 

> python.org is not the sole arbiter of official documentation in the world.

But it is the sole arbiter of official *Python* documentation.  If I am
looking at code in Python, I reasonably expect the Python docs to be
correct about that code.  Incomplete, sure, but *correct*.

>> I think code which shadows a built-in has a pretty real risk of being
>> harmful at some unspecified future point when some maintainer who hasn't
>> memorized every last line of the code makes the totally reasonable
>> assumption that basic language features are still working and available.

> Am I the only person who writes functions and methods any more? *wink*

Yes.  Everyone else converted to single giant blocks of code because they
are easier to develop.  :P

> Modern languages, and by modern I mean most languages more than, oh, about
> fifty years old, provide ways to limit the scope of variables. You don't
> need to memorise "every last line of the code" to safely edit a function.

Only the parts that are in scope, but...

I seem to recall (and I'm pretty Python newbiesh, so I could be wrong)
that Python classes create a scope in which bits of the class become
visible, and some classes are sorta biggish.

> def process(list, arg):
>     spam(list)
>     ham(arg)
>     cheese(list, arg)

> The scope of parameter "list" is limited to within the function process
> itself. Inside, it shadows the built-in list. Outside, it doesn't do squat.

Yes.  But what about the built-in spam?  :)

> Define the "entire language". Does that include the names of all the
> plethora of exceptions? How about the standard library?

I'd think "standard library" or close to it.

> For what it's worth, I don't care about memorising all the built-ins. I
> delegate that job to my editor, which has a syntax highlighter for Python.
> It never forgets built-ins. (In fact, sometimes this is a nuisance. When
> I'm editing Python 3 code, it still insists that apply and reduce are
> built-ins.)


I mostly don't use syntax highlighters; at best, they distract me, at worst,
they distract me a lot.  I also don't use one in English, although I am
sure some people would love to have nouns in blue and punctuation in green.

> Yes, and Python also encourages the use of scopes, so that the clear,
> obvious name for something in one scope does not clash with the clear,
> obvious, identical name for something completely different in another
> scope.

"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

Built-ins are not in a scope you are never not in.

> Oh there's no doubt that shadowing *can* be unsafe. But then, very few
> things can't be abused.


> As I see it, there are (at least) four stages related to shadowing.

> (1) At first, you don't even know enough to be concerned by shadowing. You
> blithely call variables "list" and "str" without a care in the world...
> until something goes wrong.

> (2) Second stage, you know enough to realise that shadowing can be bad. You
> avoid shadowing everything. Your code is full of variables called "my_list"
> and "astr" and "some_tuple". You call your functions things like "izip"
> even though it is designed as a replacement for zip, because the caller
> might use from itertools import * and accidentally replace the built-in zip
> with my zip. 

> You even avoid using "string" as a variable name because it might shadow the
> string module -- even though you haven't actually imported or used the
> string module in the last four years.

Heh.  (I got advised by pylint not to grab something from it, but I no
longer remember why; I seem to recall being totally unable to find a way
to avoid that warning and still have the string processing I needed.)

> (3) Eventually, you get frustrated writing doc strings like this:
>     def function(astr, myint=0):
>         """function(astr [, myint]) -> list
>         Arguments:
>         astr - string
>         myint - integer
>         Do something tool-like to a string and optional integer...
>         """

> and begin writing them like this:

>     def function(astr, myint):
>         """function(str [, int]) -> list
>         Do something tool-like to a string and optional integer...
>         """

That seems safe enough to me.  :)

> (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.

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.

I might feel differently about names which were only visible after you
imported some specific thing, but if we're talking built-ins that are
always visible...

Hmm.  No, actually, even then, I just think it's Bad Mojo to overlap
names that were taken by the language itself.  If a name is in a different
scope which I'm not in, I don't care about it, but if the name would already
be in scope if I didn't declare it, then I am creating a nasty ambiguity
if I use it.

Copyright 2011, all wrongs reversed.  Peter Seebach / usenet-nospam at seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.

More information about the Python-list mailing list