220 votes

Attribut d'instance nom_de_l'attribut défini en dehors de __init__

J'ai divisé le constructeur de ma classe en lui permettant d'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

Alors que mon interprète exécute mon code avec plaisir, Pylint se plaint :

Instance attribute attribute_name defined outside __init__

Une recherche rapide sur Google est actuellement infructueuse. En gardant toute la logique du constructeur dans __init__ semble mal organisé, et désactiver l'avertissement de Pylint semble également relever du piratage.

Qu'est-ce qu'un/la Pythoniques Comment résoudre ce problème ?

239voto

sthenault Points 1178

L'idée derrière ce message est de faciliter la lecture. Nous pensons trouver tous les attributs qu'une instance peut avoir en lisant son fichier __init__ méthode.

Cependant, vous pouvez toujours vouloir diviser l'initialisation en d'autres méthodes. Dans ce cas, vous pouvez simplement attribuer des attributs à None (avec un peu de documentation) dans le __init__ puis appeler les méthodes de sous-initialisation.

41voto

roippi Points 14363

Il suffit de renvoyer un tuple de parse_arguments() et les décomposer en attributs à l'intérieur de __init__ si nécessaire.

Par ailleurs, je vous recommande d'utiliser les 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]

4voto

W Kenny Points 38

La meilleure façon de répondre à cette question est de commencer par construire le paramètre dans la partie Init, Puis l'ajuster dans la partie Def

class MainApplication(tk.Frame):
    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, self.master)
        self.settingsFrame = None
        self.create_widgets(master)

    def create_widgets(self, master):
        # frame Container
        self.settingsFrame = tk.Frame(self.master, width=500, height=30, bg='white')

0voto

Ben Points 50

Pour chaque attribut que vous souhaitez définir par le biais d'une fonction, appelez la fonction à partir de l'init. Par exemple, voici ce qui fonctionne pour moi pour 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

0voto

Ofer Elboher Points 19

Bien que la définition des variables d'instance en dehors des init n'est pas recommandée en général, il existe de rares cas où elle est naturelle. Par exemple, lorsque vous avez une classe mère qui définit plusieurs variables que ses classes enfants n'utiliseront pas, et dont la définition fera perdre du temps ou des ressources à sa classe enfant, ou sera tout simplement inesthétique.

Une solution possible consiste à utiliser une fonction init-extention, que chaque classe enfant peut surcharger, et à utiliser dans cette fonction la fonction setattr afin de définir les variables d'instance propres à la classe. Cette solution n'est peut-être pas très esthétique, mais elle permet d'éviter l'avertissement de linting évoqué plus haut.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X