-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-120452: improve documentation about private name mangling #120451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Maybe it's worth linking to https://docs.python.org/3/tutorial/classes.html#private-variables? |
Oh great, there are actually |
Ok, there are some imprecision in the paragraph you just linked:
And I think I know why I always forget about the "all underscore" case... Because it's not explained here. |
There are also weird situations with import statement, which, I belive, are not described by this. Also, this explain classes named with underscores, but not identifiers within classes. Like, Additionally it might be nice to explain the goal behind mangling and applicability, but that could be a more debatable topic that require longer discussion. |
This one can indeed be important since I do not think it's ever been mentioned explicitly (like, the distinction between using the identifier via
This should be done in a separate PR IMO. There is already some kind of motivation where we justify its use for private/protected interfaces (not in those terms though).
Do you mean something like this: # .
# ├── __haha
# │ ├── hehe.py
# │ └── __init__.py
# └── __haha.py
class A1:
import __haha # fails
class A2:
import _A2__haha # impossible to import since '_A2__haha' does not exist
class A3:
import __haha.hehe # ok
A3._A3__haha # <module '__haha' from '/tmp/__haha/__init__.py'>
A3._A3__haha.hehe # <module '__haha.hehe' from '/tmp/__haha/hehe.py'>
class __:
import __haha # success
__.__haha # <module '__haha' from '/tmp/__haha/__init__.py'> |
Actually, this highlights the impossibility of importing the Footnotes
|
It's possible if you really need it: class A:
__haha = __import__("__haha") |
I don't think I will document this hack (but I'll edit my answer) but thank you! |
FTR (and for future PRs), I'm force-pushing when I'm hotfixing typos in a commit (it does not make sense to review a commit with a known error). |
Thanks, I always to prefer to know why a force push was necessary. |
In the end, I documented the hack because it feels a bit weird to say "you cannot do it" without telling you how to do it if you really need to.
Yes, and I know that maintainers don't like force-pushing (and I don't like it either when working on Sphinx, it's hard to review and my "reviewed" changes becomes messy). |
There is, and it's misread and misused to often by newcomers, which is why it would benefit from rephrasing. But I agree, that's way wider topic that clarification that this PR provides.
Yes, like this.
BTW, Murphy from mCoding made a nice video with investigation on how mangling works in different scenarios. I might have missed some cases. Not sure if YouTube links are appropriate here, but should be searchable by "Every Python dev falls for this (name mangling)" name. |
Yes, class A:
def __init__(self, haha) -> None:
setattr(self, "__haha", haha)
@property
def haha(self):
return getattr(self, "__haha")
print(A(123).haha) # 123 But that is also not documented here. |
The way I see it still makes partially sense but this is subject to interpretation. When you do a @JelleZijlstra since you have quite a good knowledge of compiler-related stuff, do you have an explanation for the second behaviour?
I don't think it's an implementation detail. The only implementation detail is when the name is longer than 255 characters and its something that is in the docs already.
That's what I added in the expressions section (so the one that should serve as the formal definition).
Actually, it's documented below in the Classes section (at the end of the paragraph). But I may move that one into the formal definition as well:
|
I'm talking about mangling rules as a whole, not
I have a hunch that in this case whole string is sent into mangling procedure and a dot prevents further actions silently. I'm too lazy to go ahead and check though. :-) |
I'll have to look at this later. @evle-zzz is probably right that the interaction with |
Thanks for making the requested changes! @JelleZijlstra: please review the changes made to this pull request. |
@JelleZijlstra Friendly ping for reviewing this one again (or drop the PR) |
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
The journey was long but I think we eventually managed to effictively improve the documentation. And I'd bet that I'll forget about it next time I'll face such issue :D |
Thanks @picnixz for the PR, and @JelleZijlstra for merging it 🌮🎉.. I'm working now to backport this PR to: 3.12, 3.13. |
…ythonGH-120451) (cherry picked from commit f4d6e45) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
GH-121715 is a backport of this pull request to the 3.13 branch. |
…ythonGH-120451) (cherry picked from commit f4d6e45) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
GH-121716 is a backport of this pull request to the 3.12 branch. |
…ython#120451) Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
I do not have a NEWS entry but tell me if I need one.
(I'm shamefully pinging @erlend-aasland since you were quite reactive a few minutes ago!)
📚 Documentation preview 📚: