Version française de ma réponse sur Stack Overflow : Python 2.7: Why does string format not work on double __ fields.

Prenons cette classe comme exemple :

class Members(object):

    def __init__(self, variable=50):
        self._myvar = variable
        self.__myvar = variable

    def get_var(self):
        return self.__myvar

L'attribut __myvar est dit privé (son nom commence par un double underscore) et l'accès en tant que tel n'est pas possible. Lorsque l'interpréteur de Python tombe sur un attribut privé, son nom est transformé (mangled) en _ClassName__attribute. Donc, pour accéder à __myvar, il faut demander _Members__myvar.

Exemples dans la console Python :

>>> m = Members()
>>> m._myvar
50
>>> m.get_var()
50
>>> m.__myvar
AttributeError: 'Members' object has no attribute '__myvar'
>>> m._Members__myvar
50

Alors, vous allez me dire : pourquoi self.get_var() arrive t-il à accéder à __myvar ? Et bien parce que lors de la compilation du code, Python connaît le contexte de la classe et traduit automatiquement le nom des attributs privés.


Et format() dans tout ça ?

Maintenant, si on veut définir la méthode de répresentation de la classe, ceci ne fonctionnera pas :

def __repr__(self):
    """ Afficher Members(xx). """
    return '{self.__class__.__name__}({self.__myvar})'.format(self=self)
>>> m = Members()
>>> m
AttributeError: 'Members' object has no attribute '__myvar'

Constat n°1 : format() n'a pas accès à l'attribut privé car le nom n'est pas complet.

Correction :

def __repr__(self):
    return '{self.__class__.__name__}({self._Members__myvar})'.format(self=self)
>>> m = Members()
>>> m
Members(50)

Aussi, tenter d'appeler get_var() ne fonctionnera pas non plus :

def __repr__(self):
    """ Afficher Members(xx). """
    return '{self.__class__.__name__}({self.get_var()})'.format(self=self)
>>> m = Members()
>>> m
AttributeError: 'Members' object has no attribute 'get_var()'

Constat n°2 : format() ne peut pas appeler une méthode.

Deux solutions s'offrent à nous :
1. Appeler la méthode en dehors du formattage :

def __repr__(self):
    return '{0}({1})'.format(self.__class__.__name__, self.get_var())

2. Depuis Python 3.60a1, la PEP 498 défini une nouvelle manière d'utiliser le formattage qui permet le « literal string interpolation ». Ça veut dire que format() pourra interpréter le code contenu dans le formattage, en gros :

def __repr__(self):
    return f'{self.__class__.__name__}({self.get_var()})'

Sources :