summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>2024-07-13 14:45:18 (GMT)
committerGitHub <noreply@github.com>2024-07-13 14:45:18 (GMT)
commitf4d6e45c1e7161878b36ef9e876ca3e44b80a97d (patch)
treeea4311c91c6c5025030a01f11e8517f83ebde88f
parent422855ad21f09b82c0bfa891dfb8fb48182c6d2b (diff)
downloadcpython-f4d6e45c1e7161878b36ef9e876ca3e44b80a97d.zip
cpython-f4d6e45c1e7161878b36ef9e876ca3e44b80a97d.tar.gz
cpython-f4d6e45c1e7161878b36ef9e876ca3e44b80a97d.tar.bz2
gh-120452: improve documentation about private name mangling (#120451)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
-rw-r--r--Doc/faq/programming.rst28
-rw-r--r--Doc/reference/expressions.rst51
-rw-r--r--Doc/tutorial/classes.rst5
3 files changed, 69 insertions, 15 deletions
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index 0a88c5f..61fbd1b 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -1741,11 +1741,31 @@ but effective way to define class private variables. Any identifier of the form
is textually replaced with ``_classname__spam``, where ``classname`` is the
current class name with any leading underscores stripped.
-This doesn't guarantee privacy: an outside user can still deliberately access
-the "_classname__spam" attribute, and private values are visible in the object's
-``__dict__``. Many Python programmers never bother to use private variable
-names at all.
+The identifier can be used unchanged within the class, but to access it outside
+the class, the mangled name must be used:
+.. code-block:: python
+
+ class A:
+ def __one(self):
+ return 1
+ def two(self):
+ return 2 * self.__one()
+
+ class B(A):
+ def three(self):
+ return 3 * self._A__one()
+
+ four = 4 * A()._A__one()
+
+In particular, this does not guarantee privacy since an outside user can still
+deliberately access the private attribute; many Python programmers never bother
+to use private variable names at all.
+
+.. seealso::
+
+ The :ref:`private name mangling specifications <private-name-mangling>`
+ for details and special cases.
My class defines __del__ but it is not called when I delete the object.
-----------------------------------------------------------------------
diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
index 95ece0e..cfada6e 100644
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -83,18 +83,47 @@ exception.
pair: name; mangling
pair: private; names
-**Private name mangling:** When an identifier that textually occurs in a class
-definition begins with two or more underscore characters and does not end in two
-or more underscores, it is considered a :dfn:`private name` of that class.
-Private names are transformed to a longer form before code is generated for
-them. The transformation inserts the class name, with leading underscores
-removed and a single underscore inserted, in front of the name. For example,
-the identifier ``__spam`` occurring in a class named ``Ham`` will be transformed
-to ``_Ham__spam``. This transformation is independent of the syntactical
-context in which the identifier is used. If the transformed name is extremely
-long (longer than 255 characters), implementation defined truncation may happen.
-If the class name consists only of underscores, no transformation is done.
+Private name mangling
+^^^^^^^^^^^^^^^^^^^^^
+When an identifier that textually occurs in a class definition begins with two
+or more underscore characters and does not end in two or more underscores, it
+is considered a :dfn:`private name` of that class.
+
+.. seealso::
+
+ The :ref:`class specifications <class>`.
+
+More precisely, private names are transformed to a longer form before code is
+generated for them. If the transformed name is longer than 255 characters,
+implementation-defined truncation may happen.
+
+The transformation is independent of the syntactical context in which the
+identifier is used but only the following private identifiers are mangled:
+
+- Any name used as the name of a variable that is assigned or read or any
+ name of an attribute being accessed.
+
+ The ``__name__`` attribute of nested functions, classes, and type aliases
+ is however not mangled.
+
+- The name of imported modules, e.g., ``__spam`` in ``import __spam``.
+ If the module is part of a package (i.e., its name contains a dot),
+ the name is *not* mangled, e.g., the ``__foo`` in ``import __foo.bar``
+ is not mangled.
+
+- The name of an imported member, e.g., ``__f`` in ``from spam import __f``.
+
+The transformation rule is defined as follows:
+
+- The class name, with leading underscores removed and a single leading
+ underscore inserted, is inserted in front of the identifier, e.g., the
+ identifier ``__spam`` occurring in a class named ``Foo``, ``_Foo`` or
+ ``__Foo`` is transformed to ``_Foo__spam``.
+
+- If the class name consists only of underscores, the transformation is the
+ identity, e.g., the identifier ``__spam`` occurring in a class named ``_``
+ or ``__`` is left as is.
.. _atom-literals:
diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst
index 1b64741..675faa8 100644
--- a/Doc/tutorial/classes.rst
+++ b/Doc/tutorial/classes.rst
@@ -688,6 +688,11 @@ 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.
+.. seealso::
+
+ The :ref:`private name mangling specifications <private-name-mangling>`
+ for details and special cases.
+
Name mangling is helpful for letting subclasses override methods without
breaking intraclass method calls. For example::