web-dev-qa-db-fra.com

Attribut d'instance nom_attribut défini en dehors de __init__

J'ai séparé mon constructeur de classe en le laissant appeler plusieurs fonctions, comme ceci:

class Wizard:
    def __init__(self, argv):
        self.parse_arguments(argv)
        self.wave_wand() # declaration omitted

    def parse_arguments(self, argv):
        if self.has_correct_argument_count(argv):
            self.name = argv[0]
            self.magic_ability = argv[1]
        else:
            raise InvalidArgumentsException() # declaration omitted

# ... irrelevant functions omitted

Tandis que mon interprète gère joyeusement mon code, Pylint a une plainte à formuler:

Instance attribute attribute_name defined outside __init__

Une recherche rapide sur Google est actuellement infructueuse. Conserver toute la logique du constructeur dans __init__ semble désorganisé, et désactiver l'avertissement Pylint semble également bidon.

Quel est un/le Pythonic moyen de résoudre ce problème?

109
Steven Liao

L'idée derrière ce message est pour des raisons de lisibilité. Nous nous attendons à trouver tous les attributs qu'une instance peut avoir en lisant sa méthode __init__.

Vous voudrez peut-être quand même diviser l’initialisation en d’autres méthodes. Dans ce cas, vous pouvez simplement affecter des attributs à None (avec un peu de documentation) dans le __init__, puis appeler les méthodes de sous-initialisation.

115
sthenault

Il suffit de renvoyer un tuple de parse_arguments() et de décompresser les attributs dans __init__ si nécessaire.

De plus, je vous recommanderais d’utiliser Exceptions au lieu d’utiliser exit(1). Vous obtenez des traces, votre code est réutilisable, etc.

class Wizard:
    def __init__(self, argv):
        self.name,self.magic_ability = self.parse_arguments(argv)

    def parse_arguments(self, argv):
        assert len(argv) == 2
        return argv[0],argv[1]
23
roippi

Pour chaque attribut que vous souhaitez définir via une fonction, appelez la fonction à partir de init. Par exemple, ce qui suit me permet de définir l’attribut ascii_txt ...

def __init__(self, raw_file=None, fingerprint=None):
    self.raw_file = raw_file
    self.ascii_txt = self.convert_resume_to_ascii()

def convert_resume_to_ascii(self):
    ret_val = self.raw_file.upper()
    return ret_val
0
Ben