0

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:

  1. 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.
  2. 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!

Community
  • 1
  • 1
Rob
  • 1,350
  • 12
  • 21
  • 3
    1. Yes, per the question you linked; and 2. No, we're all consenting adults. – jonrsharpe Jul 09 '14 at 08:40
  • Thanks @jonrsharpe. Single underscore sounds like it's as good as it gets and I'm thankful for the advice. I'd read the consenting adults phrase before, but with my C++ hat on, I'm tempted to rephrase it to "we're all forced to be slightly promiscuous adults", on the grounds that there's no real way to opt out of consent if you want to use Python ;) . – Rob Jul 09 '14 at 10:59

0 Answers0