0

I have the following class:

class Members(object):
    def __init__(self, variable=50):
        self.__myvariable = variable

    def getVariable(self):
        return self.__myvariable

    # attempt 1
    def __repr__(self):
        return """{self.__class__.__name__}({self.getVariable()})""".format(self=self)

    # attempt 2
    def __repr__(self):
        return """{self.__class__.__name__}({self.__myvariable})""".format(self=self)

I cannot find a way to print the __ variables in a format string by using the self as a key, why is that so?

The error I get is

AttributeError: 'Members' object has no attribute 'getVariable()'
AttributeError: 'Members' object has no attribute '__myvariable
Har
  • 3,727
  • 10
  • 41
  • 75

4 Answers4

3

When an attribute is private (starting with two underscores __), its real name when running is _ClassName__attribute. So, to get __myvariable, you should ask for _Members__myvariable:

def __repr__(self):
    return '{self.__class__.__name__}({self._Members__myvariable})'.format(self=self)

Examples in console:

>>> m = Members()
>>> m
Members(50)
>>> m._myvariable
50
>>> m.getVariable()
50
>>> m.__myvariable
AttributeError: 'Members' object has no attribute '__myvariable'
>>> m._Members__myvariable
50
Tiger-222
  • 6,677
  • 3
  • 47
  • 60
  • The point which I am not understanding is that if it does get mangled then how come the getVariable() is able to access it? What is the difference between getVariable in the outer scope and in the string? – Har Sep 06 '16 at 14:06
  • 1
    The function `getVariable` is created in the context of the `Members` class, and so the python compiler can change the variable name being accessed to the mangled version during compilation. The same cannot be done for the string format as the compiler doesn't know it needs to inspect the string. – Dunes Sep 06 '16 at 14:10
1

Attempt 1 fails because format function does not call method at all

Attempt 2 fails because of name mangling behavior, see PEP8

- __double_leading_underscore: when naming a class attribute, invokes name
  mangling (inside class FooBar, __boo becomes _FooBar__boo; see below).

By reading 498, which is released with 3.60a1, you can do this and you will get "Members(50)":

class Members(object):

    # attempt 3
    def __repr__(self):
        return f'{self.__class__.__name__}({self.getVariable()})'
chfw
  • 4,502
  • 2
  • 29
  • 32
  • so string format function does not understand methods only attributes ? – Har Sep 06 '16 at 14:09
  • 1
    by reading format [PEP-3101](https://www.python.org/dev/peps/pep-3101/), there isn't a line about calling method of a supplied object. You might be able to provide your own formatter, please see the custom formatter section. – chfw Sep 06 '16 at 14:15
  • see my updates regarding calling method in a formatted string. – chfw Sep 06 '16 at 14:28
0

You could format it like this instead:

    def __repr__(self):
        return "{}({})".format(self.__class__.__name__,self.getVariable())

or like this:

    def __repr__(self):
        return "{}({})".format(self.__class__.__name__,self.__myvariable)
cdarke
  • 42,728
  • 8
  • 80
  • 84
0

You can't access __myvariable because names with two leading __ get mangled (see Does Python have “private” variables in classes?)

And python doesn't do variable interpolation so the other method is not going to work either (see python string format calling a function)

You could, instead, do

return """{0}({1})""".format(self.__class__.__name__, self.getVariable())
Community
  • 1
  • 1
Eric Renouf
  • 13,950
  • 3
  • 45
  • 67