I quite like C++'s feature of having private, protected and public scopes in classes. I also like the notion of hiding implementation details from library users and preventing library API users from inadvertently messing with delicate internals (e.g. by using private
scopes, anonymous namespaces).
I know that support for this in Python is limited, and that it is source of contention: some argue that the only way privacy should be communicated is via a single underscore, _bla
, whereas others argue that that both single and double underscores should be used, _bla
for protected and __bla
for sensitive implementation details (see, for example, What is the benefit of private name mangling in Python?).
So, what I'd like to achieve, is to have a few double-underscore private members in a module, and then to access those methods from other functions and classes defined in the module scope.
Accessing private module members from public module member functions works fine, but it looks like this doesn't work (without resorting to name de-mangling or work-arounds) from within classes in the module:
#! /usr/bin/env python
def func1():
print "in func1()"
def _func2():
print "in _func2()"
def __func3():
# will be name-mangled due to leading double-underscore
print "in __func3()"
def publicFunc():
print "publicFunc() start"
__func3()
print "publicFunc() end"
class Foo:
def __init__(self):
print "Foo.__init__() start"
func1()
_func2()
__func3()
# :( Doesn't work, gives
# NameError: global name '_Foo__func3' is not defined
print "Foo.__init__() end"
publicFunc()
f = Foo()
Running the above prints this:
publicFunc() start
in __func3()
publicFunc() end
Foo.__init__() start
in func1()
in _func2()
<... stack trace>
NameError: global name '_Foo__func3' is not defined
That's not what I'd expected - I'd assumed functions and classes would have roughly the same behaviour with regards to lexical scope and mangling. I'd sort of hoped it would be roughly in line with the concept of private in C++, where I can access private detail from classes defined inside the main class, e.g.
#include <cstdio>
class A
{
public:
class B
{
public:
static void fooB() { A::foo(); }
};
private:
static void foo() { printf("in foo\n"); }
};
int main(int argc, char ** argv)
{
A::B::fooB();
}
Which prints
in foo
I'd also hoped that it might serve a similar role to that of the anonymous namespace in C++, which is really useful when writing implementation details that users of your library should not (or must not) know about.
Here are a few work-arounds I've tried. None of them strike me as particularly elegant:
_funcList = [__func3]
__funcList = [__func3]
class Foo2:
def __init__(self):
print "Foo.__init__() start"
func1()
_func2()
# __func3()
# Work-around 1 - ugly but OK for globals, but not non-locals
f3 = globals()["__func3"]
f3()
# Work-around 2 - misses the point, because now __func3 is
# readily accessible without needing to mangle method names.
# With my C++ hat on, this would be roughly equivalent to
# returning a pointer to a private member function via
# a protected member function.
_funcList[0]()
# Attempt 3 - hoping beyond hope that wrapping the method
# tag in a private list doesn't work
global __funcList
__funcList[0]()
# results in:
# NameError: global name '_Foo2__funcList' is not defined
print "Foo.__init__() end"
It seems a shame that implementation details of module classes can not access private members of the module (or have I made a mistake somewhere?).
Here are my questions:
- Is it the case that double-underscore is only really intended for preventing masking issues when sub-classing? If so then I suppose single underscores should be used in all other cases where I want to hide implementation detail.
- Is there a more elegant way of hiding implementation details where they aim is to have both the notion of a 'protected' scope and a 'private' scope?
Thanks!