Reputation: 24981
According to http://www.faqs.org/docs/diveintopython/fileinfo_private.html:
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:
#a.py
__num=1
and:
#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?
Upvotes: 343
Views: 379691
Reputation: 881655
In Python, "privacy" depends on "consenting adults'" levels of agreement - you can't force it. 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 #include
ing your .h
file is all it takes for wily coders to make hash of your "privacy"...!-))
Upvotes: 490
Reputation: 75125
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 <module_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
>>>
Upvotes: 387
Reputation: 171
See PEP8 guideline:
Method Names and Instance Variables
Use the function naming rules: lowercase with words separated by underscores as necessary to improve readability.
Use one leading underscore only for non-public methods and instance variables.
To avoid name clashes with subclasses, use two leading underscores to invoke Python’s name mangling rules.
Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.
Designing for Inheritance
Always decide whether a class’s methods and instance variables (collectively: “attributes”) should be public or non-public. If in doubt, choose non-public; it’s easier to make it public later than to make a public attribute non-public.
Public attributes are those that you expect unrelated clients of your class to use, with your commitment to avoid backwards incompatible changes. Non-public attributes are those that are not intended to be used by third parties; you make no guarantees that non-public attributes won’t change or even be removed.
We don’t use the term “private” here, since no attribute is really private in Python (without a generally unnecessary amount of work).
Upvotes: 1
Reputation: 487
Sorry if I'm late to answer, but in a module, you can define the packages to "export" like this:
mymodule
__init__.py
library.py
main.py
mymodule/library.py
# 'private' function
def _hello(name):
return f"Hello {name}!"
# 'public' function which is supposed to be used instead of _hello
def hello():
name = input('name: ')
print(_hello(name))
mymodule/__init__.py
# only imports certain functions from library
from .library import hello
main.py
import mymodule
mymodule.hello()
Nevertheless, functions can still be accessed,
from mymodule.library import _hello
print(_hello('world'))
But this approach makes it less obvious
Upvotes: 4
Reputation:
For methods: (I am not sure if this exactly what you want)
print_thrice.py
def private(method):
def methodist(string):
if __name__ == "__main__":
method(string)
return methodist
@private
def private_print3(string):
print(string * 3)
private_print3("Hello ") # output: Hello Hello Hello
other_file.py
from print_thrice import private_print3
private_print3("Hello From Another File? ") # no output
This is probably not a perfect solution, as you can still "see" and/or "call" the method. Regardless, it doesn't execute.
Upvotes: 0
Reputation: 1158
You can add an inner function:
def public(self, args):
def private(self.root, data):
if (self.root != None):
pass #do something with data
Something like that if you really need that level of privacy.
Upvotes: 34
Reputation: 11
embedded with closures or functions is one way. This is common in JS although not required for non-browser platforms or browser workers.
In Python it seems a bit strange, but if something really needs to be hidden than that might be the way. More to the point using the python API and keeping things that require to be hidden in the C (or other language) is probably the best way. Failing that I would go for putting the code inside a function, calling that and having it return the items you want to export.
Upvotes: 1
Reputation: 12745
This is an ancient question, but both module private (one underscore) and class-private (two underscores) mangled variables are now covered in the standard documentation:
The Python Tutorial » Classes » Private Variables
Upvotes: 7
Reputation: 1
Python has three modes via., private, public and protected .While importing a module only public mode is accessible .So private and protected modules cannot be called from outside of the module i.e., when it is imported .
Upvotes: -26
Reputation: 1948
This question was not fully answered, since module privacy is not purely conventional, and since using import may or may not recognize module privacy, depending on how it is used.
If you define private names in a module, those names will be imported into any script that uses the syntax, 'import module_name'. Thus, assuming you had correctly defined in your example the module private, _num, in a.py, like so..
#a.py
_num=1
..you would be able to access it in b.py with the module name symbol:
#b.py
import a
...
foo = a._num # 1
To import only non-privates from a.py, you must use the from syntax:
#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined
For the sake of clarity, however, it is better to be explicit when importing names from modules, rather than importing them all with a '*':
#b.py
from a import name1
from a import name2
...
Upvotes: 105
Reputation: 351516
Python allows for private class members with the double underscore prefix. This technique doesn't work at a module level so I am thinking this is a mistake in Dive Into Python.
Here is an example of private class functions:
class foo():
def bar(self): pass
def __bar(self): pass
f = foo()
f.bar() # this call succeeds
f.__bar() # this call fails
Upvotes: 41