2012-05-01 28 views
15

Sono abbastanza nuovo per Python e hanno una domanda per quanto riguarda la seguente classe:Le migliori pratiche quando si definiscono le variabili di istanza

class Configuration: 
    def __init__(self): 
     parser = SafeConfigParser() 
     try: 
      if parser.read(CONFIG_FILE) is None: 
       raise IOError('Cannot open configuration file') 
     except IOError, error: 
      sys.exit(error) 
     else: 
      self.__parser = parser 
      self.fileName = CONFIG_FILE 

    def get_section(self): 
     p = self.__parser 
     result = [] 
     for s in p.sections(): 
      result.append('{0}'.format(s)) 
     return result 

    def get_info(self, config_section): 
     p = self.__parser 
     self.section = config_section 
     self.url = p.get(config_section, 'url') 
     self.imgexpr = p.get(config_section, 'imgexpr') 
     self.imgattr1 = p.get(config_section, 'imgattr1') 
     self.imgattr2 = p.get(config_section, 'imgattr2') 
     self.destination = p.get(config_section, 'destination') 
     self.createzip = p.get(config_section, 'createzip') 
     self.pagesnumber = p.get(config_section, 'pagesnumber') 

E 'OK per aggiungere più variabili di istanza in un'altra funzione, get_info in questo esempio, o è buona pratica definire tutte le variabili di istanza nel costruttore? Non potrebbe portare a codice spaghetti se definisco nuove variabili di istanza ovunque?

MODIFICA: sto usando questo codice con un semplice raschietto per le immagini. Via get_section Riporto tutte le sezioni nel file di configurazione, quindi eseguo l'iterazione per visitare ogni sito da cui scarto immagini. Per ogni iterazione faccio una chiamata a get_section per ottenere le impostazioni di configurazione per ogni sezione nel file di configurazione. Se qualcuno riesce a trovare un altro approccio, andrà tutto bene! Grazie!

+0

http://stackoverflow.com/questions/2964230/python-how-should-i-make-instance-variables-available –

+0

Il 'self.__parser = None' dovrebbe essere impostato all'inizio di '__init __()'. Il motivo è che il '__init __()' è chiamato come un primo esempio di oggetto * già esistente *. Se il parser non riesce a leggere il file di configurazione e solleva l'eccezione, l'eccezione può essere rilevata da elswhere (il programma potrebbe non essere terminato). Quindi l'oggetto della classe 'Configuration' esiste ancora e il successivo' get_info() 'causerà l'errore * AttributeError: Configuration non ha attributo '__parser'. – pepr

+0

@pepr Dovrei leggere la tua risposta nel modo in cui dovrei aggiungere 'self .__ parser = None' all'inizio di' __init __. Py' o suggerisci di spostare l'inizializzazione del parser da '__init __. Py' a un'altra funzione? – happygoat

risposta

11

avrei sicuramente dichiarare tutte le variabili di istanza in __init__. Non farlo porta ad una maggiore complessità e potenziali effetti collaterali imprevisti.

Per fornire un punto di vista alternativo da David Hall in termini di accesso, questo è dallo Google Python style guide.

Access Control:

If an accessor function would be trivial you should use public variables instead of accessor functions to avoid the extra cost of function calls in Python. When more functionality is added you can use property to keep the syntax consistent

On the other hand, if access is more complex, or the cost of accessing the variable is significant, you should use function calls (following the Naming guidelines) such as get_foo() and set_foo(). If the past behavior allowed access through a property, do not bind the new accessor functions to the property. Any code still attempting to access the variable by the old method should break visibly so they are made aware of the change in complexity.

From PEP8

For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.

Note 1: Properties only work on new-style classes.

Note 2: Try to keep the functional behavior side-effect free, although side-effects such as caching are generally fine.

Note 3: Avoid using properties for computationally expensive operations; the attribute notation makes the caller believe that access is (relatively) cheap.

Python non è Java/C#, e ha molto forti idee su come potrebbe dovrebbe guardare ed essere scritta. Se stai codificando python, ha senso farlo sembrare pitone. Altre persone saranno in grado di capire il tuo codice più facilmente e sarai in grado di capire meglio anche altri codici Python.

+1

+1 perché sono d'accordo con la filosofia "Siamo tutti adulti qui" in Python. La mia principale risorsa è con le classi in cui devi sapere per chiamare una determinata funzione per mettere la classe in uno stato valido. –

+0

@DavidHall C'è stato un discorso davvero interessante negli ultimi anni con Pycón "Smetti di scrivere classi", ecco il thread delle notizie sugli hacker che ha una buona discussione su di esso. Sia il thread che il video valgono una lettura. http://news.ycombinator.com/item?id=3717715 –

+0

Cheers - darò un'occhiata. Come probabilmente puoi dire che sono uno sviluppatore C++/C# che conosce un po 'di python, quindi discussioni come questa sono ottime da leggere. –

5

Preferirei impostare tutte le variabili di istanza nel costruttore con funzioni come get_info() necessarie per mettere la classe in uno stato valido.

Con variabili di istanza pubbliche che vengono solo istanziate da chiamate a metodi come il tuo get_info(), si crea una classe che è un po 'di un campo minato da usare.

Se si è preoccupati di avere determinati valori di configurazione che non sono sempre necessari e sono costosi da calcolare (che credo sia il motivo per cui si ha get_info(), consentendo l'esecuzione differita), allora prenderei in considerazione la possibilità di rifare il sottoinsieme di config in una seconda classe o introducendo properties o funzioni che restituiscono valori.

Con le proprietà o ottieni funzioni di stile, incoraggi i consumatori della classe a passare attraverso un'interfaccia definita e migliorare l'incapsulamento .

Una volta che hai incapsulato le variabili di istanza ti dai la possibilità di fare qualcosa di più che semplicemente lanciare un'eccezione NameError - puoi forse chiamare tu stesso il numero get_info() o lanciare un'eccezione personalizzata.


1. Non si può fornire il 100% di incapsulamento con Python in quanto le variabili di istanza private indicati con un leader doppia sottolineatura sono solo privati ​​per convenzione

+0

Non vedo il vantaggio delle proprietà sulle variabili di istanza pubbliche. Puoi semplicemente rendere tutto una variabile di istanza pubblica, e se in seguito ti servirà per eseguire qualcosa di diverso dall'impostazione/acquisizione di un valore, puoi sempre convertirlo in una proprietà. – interjay

+0

Buon punto: il mio problema principale con le variabili di istanza pubbliche qui è la loro istanziazione in funzioni come get_info per classi inutilmente difficili da usare. Ma tu e Andrew Barret mi avete spostato per modificare un po 'la mia risposta, sottolineando i costruttori. –

Problemi correlati