<p>这是<a href="https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references" rel="nofollow">name mangling</a>的一个例子,在类定义中,任何在它前面有<code>__</code>的东西都被更改为<code>_classname__attr</code>。引用文件:</p>
<blockquote>
<p>Any identifier of the form <code>__spam</code> (at least two leading underscores,
at most one trailing underscore) is textually replaced with
<code>_classname__spam</code>, where classname is the current class name with
leading underscore(s) stripped. This mangling is done without regard
to the syntactic position of the identifier, as long as it occurs
within the definition of a class.</p>
</blockquote>
<p>这是在源代码级别完成的,因此可以将类定义中要使用的函数名更改为其他名称,这样就可以正常工作。你知道吗</p>
<hr/>
<p>来自<a href="https://hg.python.org/cpython/file/ca78b9449e04/Python/compile.c#l186" rel="nofollow">compile.c</a>的相关CPython代码:</p>
<pre><code>PyObject *
_Py_Mangle(PyObject *privateobj, PyObject *ident)
{
/* Name mangling: __private becomes _classname__private.
This is independent from how the name is used. */
const char *p, *name = PyString_AsString(ident);
char *buffer;
size_t nlen, plen;
if (privateobj == NULL || !PyString_Check(privateobj) ||
name == NULL || name[0] != '_' || name[1] != '_') {
Py_INCREF(ident);
return ident;
}
p = PyString_AsString(privateobj);
nlen = strlen(name);
/* Don't mangle __id__ or names with dots.
The only time a name with a dot can occur is when
we are compiling an import statement that has a
package name.
TODO(jhylton): Decide whether we want to support
mangling of the module name, e.g. __M.X.
*/
if ((name[nlen-1] == '_' && name[nlen-2] == '_')
|| strchr(name, '.')) {
Py_INCREF(ident);
return ident; /* Don't mangle __whatever__ */
}
/* Strip leading underscores from class name */
while (*p == '_')
p++;
if (*p == '\0') {
Py_INCREF(ident);
return ident; /* Don't mangle if class is just underscores */
}
plen = strlen(p);
if (plen + nlen >= PY_SSIZE_T_MAX - 1) {
PyErr_SetString(PyExc_OverflowError,
"private identifier too large to be mangled");
return NULL;
}
ident = PyString_FromStringAndSize(NULL, 1 + nlen + plen);
if (!ident)
return 0;
/* ident = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */
buffer = PyString_AS_STRING(ident);
buffer[0] = '_';
strncpy(buffer+1, p, plen);
strcpy(buffer+1+plen, name);
return ident;
}
</code></pre>