La plupart façon « pythonique » d'organiser des attributs de classe, les arguments du constructeur et les valeurs par défaut du constructeur de sous-classe?

StackOverflow https://stackoverflow.com/questions/1118006

  •  12-09-2019
  •  | 
  •  

Question

Étant relativement nouveau pour Python 2, je suis incertain de la meilleure façon d'organiser mes fichiers de classe dans la façon la plus « pythonique ». Je ne poserais pas cela, mais le fait que Python semble avoir assez peu de moyens de faire les choses qui sont très différentes de ce que je suis venu à attendre des langues que je suis habitué.

Dans un premier temps, je traitais des classes comment juste je l'habitude de les traiter en C # ou PHP, ce qui bien sûr m'a fait trébucher dans tous les sens quand j'ai découvert finalement les valeurs mutables Gotcha:

class Pants(object):
    pockets = 2
    pocketcontents = []

class CargoPants(Pants):
    pockets = 200

p1 = Pants()
p1.pocketcontents.append("Magical ten dollar bill")
p2 = CargoPants()

print p2.pocketcontents

Aïe! Ne m'y attendais pas!

J'ai passé beaucoup de temps à la recherche sur le web et par une source pour d'autres projets pour des conseils sur la meilleure façon d'organiser mes cours, et l'une des choses que je remarqué est que les gens semblent déclarer un grand nombre de leurs variables d'instance - mutable ou autrement - dans le constructeur, et empiler aussi les arguments du constructeur par défaut sur tout à fait en couche épaisse.

Après avoir développé comme celui-ci pendant un certain temps, je suis toujours laissé me gratter la tête un peu le manque de connaissance de celui-ci. Compte tenu de la longueur à laquelle le langage python va à faire les choses semblent plus intuitive et évidente, il me semble carrément étrange dans les rares cas où j'ai un assez grand nombre d'attributs ou beaucoup d'arguments du constructeur par défaut, surtout quand je « m subclassing:

class ClassWithLotsOfAttributes(object):
    def __init__(self, jeebus, coolness='lots', python='isgoodfun', 
             pythonic='nebulous', duck='goose', pants=None, 
             magictenbucks=4, datawad=None, dataload=None,
             datacatastrophe=None):

        if pants is None: pants = []
        if datawad is None: datawad = []
        if dataload is None: dataload = []
        if datacatastrophe is None: datacatastrophe = []
        self.coolness = coolness
        self.python = python
        self.pythonic = pythonic
        self.duck = duck
        self.pants = pants
        self.magictenbucks = magictenbucks
        self.datawad = datawad
        self.dataload = dataload
        self.datacatastrophe = datacatastrophe
        self.bigness = None
        self.awesomeitude = None
        self.genius = None
        self.fatness = None
        self.topwise = None
        self.brillant = False
        self.strangenessfactor = 3
        self.noisiness = 12
        self.whatever = None
        self.yougettheidea = True

class Dog(ClassWithLotsOfAttributes):
    def __init__(self, coolness='lots', python='isgoodfun', pythonic='nebulous', duck='goose', pants=None, magictenbucks=4, datawad=None, dataload=None, datacatastrophe=None):
        super(ClassWithLotsOfAttributes, self).__init__(coolness, python, pythonic, duck, pants, magictenbucks, datawad, dataload, datacatastrophe)
        self.noisiness = 1000000

    def quack(self):
        print "woof"

Doux niaiserie côté (je ne peux pas vraiment me aider lors de la cuisson jusqu'à ces classes par exemple artificiels), en supposant que j'ai un monde réel besoin pour un ensemble de classes avec ces nombreux attributs, je suppose que mes questions sont:

  • Quel est le plus, uhh, façon « pythonique » de déclarer une classe avec que de nombreux attributs? Est-il préférable de les mettre contre la classe si la valeur par défaut est immuable, ala Pants.pockets, ou est-il préférable de les mettre dans le constructeur, ala ClassWithLotsOfAttributes.noisiness?

  • Y at-il un moyen d'éliminer la nécessité de redéclarer les valeurs par défaut pour tous les arguments du constructeur de sous-classe, comme dans Dog .__ init__? Dois-je être encore compris ce beaucoup d'arguments avec défaut de toute façon?

Était-ce utile?

La solution

  • Si les attributs varient d'une instance à l'instance en font par exemple attribuer à savoir les créer inside__init__ en utilisant auto autre si elles doivent être partagée entre les instances de classe comme une constante, les mettre à la classe niveau.

  • Si votre classe a vraiment besoin de passer, donc de nombreux arguments en __init__, laissez obtenir la liste des arguments de l'utilisation de classe et arguments clés par exemple.

class Dog(ClassWithLotsOfAttributes):
    def __init__(self, *args , **kwargs):
        super(ClassWithLotsOfAttributes,    self).__init__(*args , **kwargs)
        self.coolness = "really cool!!!
  • Pas besoin de passer toutes les variables, sauf quelques unes importantes, __init__, la classe peut prendre un certain par défaut et l'utilisateur peut les changer plus tard si nécessaire.
  • A l'aide de 4 espaces au lieu d'onglet.

  • si vous avez besoin d'ajouter une morsure arg supplémentaire, Dog et mot-clé arg trop vieux

class CoolDog(ClassWithLotsOfAttributes):
    def __init__(self, bite, *args , **kwargs):
        self.old = kwargs.pop('old', False) # this way we can access base class args too
        super(ClassWithLotsOfAttributes,    self).__init__(*args , **kwargs)
        self.bite = bite
        self.coolness = "really really cool!!!

différentes façons useCoolDog

CoolDog(True)
CoolDog(True, old=False)
CoolDog(bite=True, old=True)
CoolDog(old=True, bite=False)

Autres conseils

Il est possible que vous pouvez briser vos classes massives vers le bas en classes qui effectuent chacun une seule tâche simple. En général, les classes ne ont pas besoin ces nombreux attributs.

Si vous avez vraiment besoin d'avoir que beaucoup d'attributs, je pense que vous aurez à vivre avec leur assignant trop, d'autant plus que vous avez besoin des valeurs par défaut pour tous. Vous n'avez pas besoin de réaffecter les valeurs par défaut dans vos sous-classes bien (je vois Anurag Uniyal a montré comment.)

Vous devriez les affecter à self cependant, et non comme attributs de classe. Notez la différence:

class Class1(object):
    attr1 = 'abc'

class Class2(object):
    def __init__(self):
        self.attr1 = 'abc'

Class1.attr1 # returns 'abc'
c = Class1()
c.attr1 # Also returns 'abc'
Class1.attr1 = 'def'
c.attr1 # Returns 'def'!
c.attr1 = 'abc' # Now the c instance gets its own value and will show it
                # independently of what Class1.attr1 is. This is the same
                # behavior that Class2 exhibits from the start.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top