1

I am playing around with python's namespacing and I have come across some behaviour I can't explain. In particular I wanted to see if you can stop classes being imported with a command like 'from module import *'. In one module, call it moduleA, I have the following:

class __hi(object): pass

class hey(object):

    def __init__(self):
        # self.hey = __hi()

Then in another module, say moduleB, I import 'everything' from moduleA with

from moduleA import *

This has the desired effect of importing the class 'hey' but not the class __hi.

Now when the line above '# self.hey = __hi()' is uncommented I get an error I don't understand:

"NameError: global name '_hey__hi' is not defined"

It looks as though python has mangled the variable name because the class name has a double underscore. Can anyone explain this?

This question is completely different from that which is referenced. In the linked post presented the name is mangled with the class variable in which the mangled variable is living. That is not what I am asking about.

Edit:

Thanks to vaultah for pointing out that: It doesnt matter where the double-underscore is in the line it will still trigger name-mangling - but could anyone explain why this is the case? It means that, in (highly contrived) situations like the one above, you can never save an instance of a class in another class.

JMzance
  • 1,704
  • 4
  • 30
  • 49
  • Why don't you just use `__all__`? Or a single leading underscore? – jonrsharpe Jan 31 '16 at 17:56
  • It's not a technical problem I'm trying get around - I just dont understand the above behaviour – JMzance Jan 31 '16 at 17:56
  • 1
    You appear to understand name mangling, so what has surprised you? – jonrsharpe Jan 31 '16 at 17:57
  • Because the variable self.hey shouldn't, so far as I understand, be name-mangled at all. The variable name has no underscores in it at all, only the name of the class instance which is being stored in self.hey has underscores – JMzance Jan 31 '16 at 18:00
  • @jonrsharpe - the __all__thing is cool as a solution. But I'm more curious about the name mangling. – JMzance Jan 31 '16 at 18:02
  • Yeah so I guessed that was going on by simply reading the python runtime error, but why does having underscores to the right of the assignment (for lack of a better way of phrasing it) trigger that lookup? It should clearly just look for '__hi'. If I was doing self.__hey = __hi() *then* I would expect it to mangle the name – JMzance Jan 31 '16 at 18:05
  • @vaultah can you remove the duplicate please (or explain how the answer in the other post explains this) – JMzance Jan 31 '16 at 18:10
  • I just don't understand why you would ever want to trigger mangling unless the double underscore was on the LHS of the assignment. – JMzance Jan 31 '16 at 18:15
  • Because with the behaviour as it currently works you can never save an instance of the class '__hi' to a variable in another python class. – JMzance Jan 31 '16 at 18:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102166/discussion-between-jmzance-and-vaultah). – JMzance Jan 31 '16 at 19:06

1 Answers1

0

The problem occurs because double underscores are mangled when they are encountered inside a class.

Your class hey includes the line self.hey = __hi(), and because it is within a class the __hi gets mangled to _hey__hi, which fails.

You could solve this by replacing __hi with single-underscore _hi, or removing the underscores, or any of a number of other ways. You could declare your helper class within a block that exits and destroys the name before the file is finished parsing:

def create_hey():
    class __hi:
        pass

    x = __hi

    class hey:
        def __init__():
            self.__hi = x()

    return hey

hey = create_hey()

Realistically, though, that's a lot of work. You're better off as numerous commenters have suggested, simply defining __all__ so as to control what may be imported:

__all__ = [ 'hey' ]
aghast
  • 14,785
  • 3
  • 24
  • 56