0

I know that there is no such thing as true private in Python for sometimes you need to following:

  • prevent people from calling some methods or warn them when they do, but allow them to be called from other modules
  • detect where these methods are used and raise an warning on the console or even an exception, this would allow you to start marking methods to private without breaking existing code.
  • hide the private methods from IDE auto-complete (optional) - probably by using one underline before its name. Now I'm wondering if someone found a beautiful way to obtain this behaviour, maybe one that use annotations?

Please remember that this has to work with existing codebase, so it should support a gradually re factoring of the existing code.

The last point is almost solved, the only question about it is if I should use one underscore or two underscores?

2
  • How do you make the distinction in #1? #2 will be IDE-specific. #3 may be possible, but will generate bogus warnings (unless you take the extra pain to distinguish "legitimate" callers from the rest, and even odds are it won't be perfect in any sense of the word) and sounds like deprecation rather than privacy anyway. Why not just change the name? Prepend an underscore, nothing says "private" like that. Commented Nov 2, 2011 at 11:47
  • 1
    Just use one underscore - the name mangling that gets triggered by the double underscore will cause way more headaches than it will solve. Commented Nov 2, 2011 at 12:06

4 Answers 4

7

Python has the philosophy of "consenting adults": Prefix methods with an underscore to mark them as private. Don't call any methods with a leading underscore from the outside. If you do, you're on your own. You are free to do so, but you have been warned.

To adopt this convetion in an existing code base, rename the original methods to names with a leading underscore, and add a wrapper with the original name that throws a warning.

Your IDE should have configurable auto-completion. If not, use Emacs :)

Sign up to request clarification or add additional context in comments.

1 Comment

@Paul: The Emacs part was more of a joke. I really and honestly don't care what other people use to edit their code. vi is also fine. :)
1

Hiding from autocomplete is going to completely depend on your editor and how it handles autocomplete. My editor does not do autocomplete so I wouldn't need to use it.

The standard python convention is to prefix and underscore to the method name. This tells the user that the method is private and shouldn't be used.

You can use double underscores before the method name; this will invoke name mangling.

See 9.7 on this page for details: http://docs.python.org/tutorial/classes.htm.

But it's still not private; it can be called.

As far raising exceptions look into the inspect object and frame info. There are a ton of q and as on this site about that.

tl;dr You can't make anything private but you can make it harder to find

1 Comment

Double underscores before the name trigger name mangling. Double underscores before and after the name are reserved names which shouldn't be used (except for the predefined ones, of course).
0

Maybe define your private methods on an internal class, and access it internally using self._private.method:

class PublicObject(object): class PrivateObject(object): def __init__(self, public): self.public = public def private1(self): print "a private method, not visible outside the public wrapper on", id(self.public) def __init__(self): self._private = self.PrivateObject(self) def public1(self): print "a public method, which invokes a private one" return self._private.private1() a = PublicObject() print dir(a) # only shows public1, not private1; won't show private1 in most IDEs autocomplete a.public1() a.private1() # raises an exception a._private.private1() # still possible to call private methods, but obvious when you are doing so 

If you wanted ProtectedObject with visibility up the inheritance chain, create a similar _protected attribute and use __getattr__ to access attributes and methods on super(PublicObject,self.public)._protected.

By the way, what you are asking is really outside the Python philosophy, and adding this indirection through a composite object will incur a performance cost.

Comments

0

You can decorate the private methods with a call to warnings.warn.

I'm not sure what you mean by preventing people but allowing modules to call methods. Is the distinction that one happens at an interactive prompt, but the other does not? If so, you can test if python is being run from an interactive prompt by checking the value of sys.path[0].

When python runs a script, sys.path[0] equals the directory of the script. When python runs an interactive session, sys.path[0] is set to the empty string ''. So, to warn people, but not scripts, you could do

import warnings import functools def warn_private(func): if not sys.path[0]: @functools.wraps(func) def wrapper(self,*args,**kwargs): warnings.warn('{f} is private'.format(f=func.__name__)) return func(self,*args,**kwargs) return wrapper else: return func class Foo(object): @warn_private def _bar(self): pass 

3 Comments

Won't this warn even for legitimate internal calls to _bar from within Foo?
@PaulMcGuire: Your question is addressed by the second part of my answer. Since I posted in two stages, perhaps it wasn't present when you posted the comment.
@unutbu: Sorry for that one. I hoped you didn't see it :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.