2009-07-13 12 views
13

Essendo relativamente nuovo per Python 2, sono incerto sul modo migliore per organizzare i miei file di classe nel modo più "pythonic". Non lo chiederò a questo, ma al fatto che Python sembra avere diversi modi di fare cose che sono molto diverse da quello che mi sono aspettato dalle lingue a cui sono abituato.La maggior parte dei metodi "pythonic" per organizzare gli attributi di classe, gli argomenti del costruttore e le impostazioni predefinite del costruttore di sottoclassi?

Inizialmente, stavo solo trattando le classi come avrei solito li tratto in C# o PHP, che ovviamente mi ha fatto inciampare in tutto il posto quando ho finalmente scoperto i valori mutevoli 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 

Yikes! Non me l'aspettavo!

Ho passato molto tempo a cercare sul Web e attraverso qualche fonte per altri progetti suggerimenti su come organizzare al meglio le mie lezioni, e una delle cose che ho notato è che le persone sembrano dichiarare molto della loro istanza variabili - mutabili o meno - nel costruttore e anche gli argomenti del costruttore di default sono abbastanza spesso.

Dopo essermi sviluppato in questo modo per un po ', sono ancora lasciato a grattarmi la testa un po' per la mancanza di familiarità. Considerando le lunghezze a cui il linguaggio Python va per rendere le cose più intuitive e ovvie, mi sembra strano nei pochi casi in cui ho un sacco di attributi o un sacco di argomenti di costruzione predefiniti, specialmente quando 'm sottoclassi:

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" 

stupidità Mild da parte (non posso davvero aiutare me stesso quando cucinando queste classi esempio artificiali), assumendo ho un mondo reale necessità di un insieme di classi con questo molti attributi, ho supporre le mie domande sono:

  • Qual è la, uhh, modo più 'divinatorio' di dichiarare una classe con che molti attributi? È meglio metterli contro la classe se il valore predefinito è immutabile, a capo Pants.pockets, o è meglio metterli nel costruttore, a parte ClassWithLotsOfAttributes.noisiness?

  • C'è un modo per eliminare la necessità di ridenominare i valori predefiniti per tutti gli argomenti del costruttore della sottoclasse, come in Dog .__ init__? Dovrei anche includere in questo caso molti argomenti con le impostazioni predefinite?

+0

+1 Devo amare i tuoi attributi di esempio. Inoltre, buona domanda. – balpha

risposta

4
  • Se gli attributi varieranno da caso ad esempio renderli esempio attributo cioè li creano all'interno __init__ utilizzando altrimenti se devono essere condivisa tra istanze di classe come una costante, metterli a livello di classe .

  • Se la classe davvero bisogno di passare, così molti argomenti in __init__, lasciate derivano classe lista uso argomenti e argomenti chiave per esempio

class Dog(ClassWithLotsOfAttributes): 
    def __init__(self, *args , **kwargs): 
     super(ClassWithLotsOfAttributes, self).__init__(*args , **kwargs) 
     self.coolness = "really cool!!!
  • Non c'è bisogno di passare tutte le variabili, tranne alcune fra le più importanti, in __init__, classe può assumere alcuni default e l'utente li può cambiare in seguito, se necessario.
  • Utilizzare 4 spazi anziché tab.

  • se è necessario aggiungere un morso arg in più, a Dog e la parola chiave arg troppo vecchio

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!!!

vari modi si useCoolDog

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

sarà un esperto di formattazione, formattare correttamente il codice? –

+0

oh non sapevo che potevi usare * args e ** kwargs in quel modo! 'coolness' ha sicuramente bisogno di essere alzato per 'veramente cool !!!' :) – Shabbyrobe

+0

inoltre, che dire del caso in cui Dog .__ init__ ha bisogno di aggiungere un ulteriore argomento costruttore? è def__init __ (self, legs = 4, * args, ** kwargs) il modo giusto per farlo? – Shabbyrobe

-1

E 'possibile che si può rompere le tue massicce classi in classi che eseguono ciascuna solo un compito semplice. Di solito le classi non hanno bisogno di questi molti attributi.

Se hai davvero bisogno di avere tanti attributi, penso che dovrai vivere con l'assegnazione di tutti anche, soprattutto perché hai bisogno di valori predefiniti per tutti. Non è necessario riassegnare i valori predefiniti nelle sottoclassi (vedo come Anurag Uniyal ha mostrato come).

Si consiglia di assegnarli a self e non come attributi di classe. Notare la differenza:

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. 
Problemi correlati