Like most languages, Python has the concept of private elements:
- Private functions, which can't be called from outside their module
However, if I define two files:
#b.py import a print a.__num
when i run
b.py it prints out
1 without giving any exception. Is diveintopython wrong, or did I misunderstand something? And is there some way to do define a module's function as private?
In Python, "privacy" depends on "consenting adults'" levels of agreement - you can't force it (any more than you can in real life;-). A single leading underscore means you're not supposed to access it "from the outside" -- two leading underscores (w/o trailing underscores) carry the message even more forcefully... but, in the end, it still depends on social convention and consensus: Python's introspection is forceful enough that you can't handcuff every other programmer in the world to respect your wishes.
((Btw, though it's a closely held secret, much the same holds for C++: with most compilers, a simple
#define private public line before
.h file is all it takes for wily coders to make hash of your "privacy"...!-))
There may be confusion between class privates and module privates.
A module private starts with one underscore
Such a element is not copied along when using the
from <module_name> import * form of the import command; it is however imported if using the
import <moudule_name> syntax (see Ben Wilhelm's answer)
Simply remove one underscore from the a.__num of the question's example and it won't show in modules that import a.py using the
from a import * syntax.
A class private starts with two underscores (aka dunder i.e. d-ouble under-score)
Such a variable has its name "mangled" to include the classname etc.
It can still be accessed outside of the class logic, through the mangled name.
Although the name mangling can serve as a mild prevention device against unauthorized access, its main purpose is to prevent possible name collisions with class members of the ancestor classes. See Alex Martelli's funny but accurate reference to consenting adults as he describes the convention used in regards to these variables.
>>> class Foo(object): ... __bar = 99 ... def PrintBar(self): ... print(self.__bar) ... >>> myFoo = Foo() >>> myFoo.__bar #direct attempt no go Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Foo' object has no attribute '__bar' >>> myFoo.PrintBar() # the class itself of course can access it 99 >>> dir(Foo) # yet can see it ['PrintBar', '_Foo__bar', '__class__', '__delattr__', '__dict__', '__doc__', '__ format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__ ', '__subclasshook__', '__weakref__'] >>> myFoo._Foo__bar #and get to it by its mangled name ! (but I shouldn't!!!) 99 >>>