0

I'm passing a function as a parameter to a class constructor. The constructor stores it in an instance variable, and other class methods want to call it.

class ComboList(list) :
    def __init__(self,a,b,kg) :
        list.__init__(self)
        self.__kg = kg
        # More stuff follows

When I try to call the function in another method, for example:

x = self.__kg('a')

I get "{AttributeError}'' object has no attribute '__kg'."

When I evaluate the function call in my IDE's Evaluate Expression window, I get the same thing. But when I evaluate the instance variable itself ("self.__kg"), I get:

result = {function} <function <lambda> at 0x0000000002ED5C18>

...so it appears that the attribute __kg is defined.

What is going wrong?

I can call the function by referencing the parameter -- no problem.

kg(a')

I can also assign the parameter's value to a method variable and call the variable -- no problem.

_kag = kg
_kag('a')

It's only the reference to the instance variable that doesn't work.

Jonathan Sachs
  • 613
  • 8
  • 19
  • This is [**name mangling**](https://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_Python) - try `_ComboList__kg`. Or just ditch the double underscores. – jonrsharpe Jun 18 '15 at 16:20
  • Can you please update the code where you are creating object of `ComboList` and calling the kg function? – Anand S Kumar Jun 18 '15 at 16:39
  • jonrsharpe, that makes sense but it's surprising. I know name mangling is supposed to make variables hard to get by accident outside the scope object where they're defined. I didn't expect it to make the hard to get on purpose WITHIN the scope object. @Anand, it's not clear what kind of update you mean. The code hasn't changed in any relevant way. If this is still want, please clarify and I'll try to accommodate you. – Jonathan Sachs Jun 18 '15 at 22:13
  • I mean i tried your simplified approach in python 3.3, and it does not give me any error, can you update atleast the complete method , where you are doing `x = self.__kg('a')` – Anand S Kumar Jun 19 '15 at 03:49

2 Answers2

1

Whenever a variable has a double underscore in a class, Python will invoke name mangling (see the Python documentation on classes). Using double underscores is pretty much only to avoid name clashes with subclasses or to make a variable 'really private'. (See PEP8 for more style suggestions).

If you want other inherited subclasses to use your private variable, you can either use one single underscore (_kg) or use the @property decorator.

Check out this really dumb example:

class ComboList(list) :
    def __init__(self,a,b,kg) :
        list.__init__(self)
        self.__kg = kg
        # More stuff follows

    @property
    def kg(self):
        return(self.__kg)

my_list = ComboList(1,2,'This will be printed')
print(my_list.kg)
1

Don't use double underscore, which makes python do some magic and append classname to variable names (called name mangling). Just use single underscore instead of double.

hspandher
  • 15,934
  • 2
  • 32
  • 45