>>> class Foo:
def __fn(self):
return 2
>>> Foo().__fn()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__fn'
>>> Foo()._Foo__fn()
2
A single underscore is more like 'protected', ie. it doesn't prevent subclasses from easily/accidentally overriding your function.Python keeps code much smaller but above a certain size I wish I could "promote" parts of my code to Java.
Partial typing in Python just isn't close to feeling the same.
There are many benefits to enforcing privacy, and one of the biggest ones is that you can make changes to the internals of your library without breaking your users' code, because they never had access to the internals.
Don't stop me from patching your buggy code. If writing an extension is more efficient, that's how I'd solve the problem.
Of course, if you have a perfect understanding of the code, this will never be a problem, as the program is always executed as it is written. But most likely, not everyone in your organization will be as patient, smart and attentive to the details as you are.
It's a way for the class user to say "I know this is terrible, I know this might break, I want to do it anyway".
There are both declaritive and command line param ways to open things so it's not as rigid as it sounds.
Encapsulation. In Python you can write code in an OO style and benefit from inheritance, but it’s really only good for people writing libraries and frameworks. For end user code, objects are best avoided because they can pick up state in unexpected ways, which leads to problems that are extremely difficult to debug.
class Foo():
def __init__(self):
self.bar = 1
Then let's say you have foo_instance imported in your module, and you see that foo_instance.bar has a value of 2.You can see that foo_instance is imported from module A. So you go there, and see that the instance wasn't created there, it was imported from module B. But wait, it wasn't created there either, it was imported from module C, etc.
Somewhere along the way bar picked up the value of 2. But it's almost impossible to figure out where because there isn't any requirement use a uniquely-named accessor to modify the instance, so you can't just grep through the code to see where that method was called. (And maybe the name of the instance has changed a few times along the way, for whatever reason.)
And what's worse, the code that modified the instance might not even be visible in any of the modules, it's possible that someone took advantage of Python's ability to change the way the importing system works to mess with either the class or the instance. Or maybe there is some global middleware that's messing with objects or instances, or unrelated module Z is secretly monkey patching module B somewhere in the middle of this process. Who knows, and good luck figuring out.
Whereas if you just write the user-code logic in functions then it's not possible for developers to create situations like this. That obviously isn't possible for a library where the entire point is to make everything extensible and where you don't know how people will want to use something in advance, but hopefully the people writing libraries and frameworks have good enough judgment not to completely abuse the tools.
I'm not sure if I can really articulate how this is different than Java or Swift or whatever, but for whatever reason it just feels different.
You can make instance variables "culturally private" by pretending the variable name with a single underscore, and you can name-mangle (to make it effectively private, unless someone really goes out of their way) with double underscores, but I know that's annoying to do for most/all variables and that making them private by default has advantages.
Python is just not as strict a language as Java, Swift, C#, etc. That has advantages and disadvantages.
Personally, this hasn't generally been an issue for me, because I've rarely directly modified instance variables in my own code unless I'm intentionally doing something really "meta", and it's not a pattern I've seen much of in other codebases.