Search code examples
pythonfunction-pointersencapsulation

Reference to (module only) global function within a class method


In python one can easily refer to a global method by means of it's name.

def globalfoo(a):
    print(a)


class myClass:
    def test(self):
        v = globalfoo
        v("hey")

t = myClass()
t.test()

Now in python one can also "hide" a (class) method by prefixing it with two underscores. - And I thought(!) one could do the same for global functions - to make a global function module-only. (Similar to C++ where one can decide to put a function declaration not in the header so it's only visible to the current compilation unit).

I then tried to combine this:

def __globalfoo(a):
    print(a)


class myClass:
    def test(self):
        v = __globalfoo
        v("hey")

t = myClass()
t.test()

However this doesn't seem to work, an error is thrown that "_myCLass__globalfoo" is undefined. So how would I make both things work: having a reference to a function. And hiding the function from the external scope?
Is a static method in this case the only/best solution?


Solution

  • And I thought(!) one could do the same for global functions - to make a global function module-only.

    You were incorrect. Using a double-underscore name for a module-level function will not prevent it from being used in other modules. Someone can still do import yourmodule and then call yourmodule.__globalfoo.

    The double-underscore name mangling behavior is defined in the docs:

    Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

    It is purely a textual substitution and takes no account of what (if anything) the double-underscore name refers to. It just takes any identifier occurring anywhere inside the class definition that looks like __blah and changes it to _class__blah. It is specific to class definitions and does not occur for module-level functions.

    The best thing to do is prefix your function with a single underscore and document that it is not part of the public API and users of the module should not rely on it. There is nothing to be gained by attempting to "enforce" this privacy.