2011-01-22 8 views
82

Ho una linea di codice che segue (non colpa per le convenzioni di denominazione, non sono miei):Come rompere una linea di metodi concatenati in Python?

subkeyword = Session.query(
    Subkeyword.subkeyword_id, Subkeyword.subkeyword_word 
).filter_by(
    subkeyword_company_id=self.e_company_id 
).filter_by(
    subkeyword_word=subkeyword_word 
).filter_by(
    subkeyword_active=True 
).one() 

non mi piace come sembra (non troppo leggibile), ma I don' Ho un'idea migliore per limitare le linee a 79 caratteri in questa situazione. C'è un modo migliore di romperlo (preferibilmente senza barre inverse)?

risposta

171

Si potrebbe utilizzare ulteriore parentesi:

subkeyword = (
     Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word) 
     .filter_by(subkeyword_company_id=self.e_company_id) 
     .filter_by(subkeyword_word=subkeyword_word) 
     .filter_by(subkeyword_active=True) 
     .one() 
    ) 
+0

Mi piace anche di più. Non aggiunge altro codice e non ha barre retroverse. –

+13

Non sai cosa giustifica il rientro extra qui; Penso che questa soluzione si sposti perfettamente con le linee sospese rientrate una sola volta e il parente finale non lo è affatto. –

+0

A mio parere, il doppio indentazione è utile qui perché è visivamente distinto da un normale blocco rientrato. Quando è circondato da un altro codice, ciò rende più ovvio che si tratta di una singola linea avvolta. – sth

9

Basta memorizzare il risultato/oggetto intermedio e invocare il metodo successivo su di esso, ad es.

q = Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word) 
q = q.filter_by(subkeyword_company_id=self.e_company_id) 
q = q.filter_by(subkeyword_word=subkeyword_word) 
q = q.filter_by(subkeyword_active=True) 
subkeyword = q.one() 
+4

Questo funziona bene per qualcosa di simile a una query, ma come un modello generale, io non sono così sicuro. Ad esempio, quando si concatena in Beautiful Soup come 'team_members = soup.find (class _ = 'team di sezione'). Find_all ('ul'). Find_all ('li')', il valore restituito da ciascun '.find (.. .) La chiamata non corrisponde ancora al significato di "team_members". –

4

Secondo Python Language Reference
È possibile utilizzare una barra rovesciata.
O semplicemente romperlo. Se una parentesi non è accoppiata, Python non la tratterà come una linea. E in tali circostanze, l'indentazione delle seguenti righe non ha importanza.

1

te sembra usando SQLAlchemy, se è vero, sqlalchemy.orm.query.Query.filter_by() metodo prende più argomenti di parole chiave, così si potrebbe scrivere come:

subkeyword = Session.query(Subkeyword.subkeyword_id, 
          Subkeyword.subkeyword_word) \ 
        .filter_by(subkeyword_company_id=self.e_company_id, 
           subkeyword_word=subkeyword_word, 
           subkeyword_active=True) \ 
        .one() 

Ma sarebbe meglio:

subkeyword = Session.query(Subkeyword.subkeyword_id, 
          Subkeyword.subkeyword_word) 
subkeyword = subkeyword.filter_by(subkeyword_company_id=self.e_company_id, 
            subkeyword_word=subkeyword_word, 
            subkeyword_active=True) 
subkeuword = subkeyword.one() 
+0

+1 per il suggerimento di SQLAlchemy filter_by(). Va bene per questo esempio, ma io uso spesso filter() che accetta solo una condizione. –

11

La mia scelta personale sarebbe:

 
subkeyword = Session.query(
    Subkeyword.subkeyword_id, 
    Subkeyword.subkeyword_word, 
).filter_by(
    subkeyword_company_id=self.e_company_id, 
    subkeyword_word=subkeyword_word, 
    subkeyword_active=True, 
).one() 
+0

Sono d'accordo se ci sono molti parametri passati ma sembra brutto quando i parametri 0 o 1 sono comuni. Ad esempio: https://gist.github.com/andybak/b23b6ad9a68c7e1b794d –

+1

Sì, quello stile ha casi degenerati (come qualsiasi stile). Non vorrei rompere su tutti i parens aperti. Nulla di ciò mi rende felice, ma qui ci sono alcuni casi: https://gist.github.com/pkoch/8098c76614765750f769 – pkoch

38

Questo è un caso in cui una linea di continuazione charac è preferibile aprire le parentesi. La necessità di questo stile diventa più evidente come nomi di metodo si allungano e come metodi iniziare a prendere argomenti:

subkeyword = Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word) \ 
        .filter_by(subkeyword_company_id=self.e_company_id)   \ 
        .filter_by(subkeyword_word=subkeyword_word)     \ 
        .filter_by(subkeyword_active=True)       \ 
        .one()              \ 

PEP 8 è destinato ad essere interpretato con una misura di buon senso e un occhio sia per la pratica e la bellissimo. Violare felicemente qualsiasi linea guida PEP 8 che risulta in un codice brutto o difficile da leggere.

Detto questo, se vi trovate spesso in contrasto con PEP 8, può essere un segno che ci sono problemi di leggibilità che trascendono la vostra scelta di spazi bianchi :-)

+2

+1 su barre rovesciate e allineamento dei filtri concatenati in questo caso particolare. Questa situazione si presenta anche a Django ed è più leggibile in questo modo - ma in ogni altra situazione mi sento come se le frasi parentesi fossero superiori (non soffrire del problema "c'è spazio bianco dopo il mio backslash?"). Detto questo, è possibile utilizzare la frase parentesi per ottenere lo stesso effetto, ma ti mette in modalità di lettura Lisp nel mezzo della lettura di Python, che trovo sconcertante. – zxq9

+7

Non vedo come questa soluzione sia in grado di far fronte "come i nomi dei metodi si allungano e come i metodi iniziano a prendere argomenti" rispetto al "wrap in outer parens" o "line-break dopo ogni paren aperto e prima di ogni close paren "soluzioni. In effetti è peggio quando lo maneggia, dato che (almeno come mostrato qui) richiede un rientro molto più profondo per ogni linea sospesa. –

+1

Troppo eccessivo per le chiamate filtro. Una tabulazione o 4 spazi sarebbero stati sufficienti qui. Anche l'allineamento di '\' ... Quanti secondi hai tenuto premuto su quella chiave spaziale? Generalmente sono contro tutti i modi, che richiedono di battere quella chiave spaziale come se non ci fosse un domani. – Zelphir

4

E 'un po' di una soluzione diversa rispetto fornito da altri, ma uno dei miei preferiti dal momento che porta a volte metaprogramming elegante.

base = [Subkeyword.subkeyword_id, Subkeyword_word] 
search = { 
    'subkeyword_company_id':self.e_company_id, 
    'subkeyword_word':subkeyword_word, 
    'subkeyword_active':True, 
    } 
subkeyword = Session.query(*base).filter_by(**search).one() 

Questa è una buona tecnica per la ricerca di edifici. Passare da un elenco di condizionali al mio dal tuo modulo di query complesso (o deduzioni basate su stringhe su ciò che l'utente sta cercando), quindi esplodere il dizionario nel filtro.

1

mi piace per far rientrare gli argomenti con i due blocchi, e la dichiarazione di un blocco, come questi:

for image_pathname in image_directory.iterdir(): 
    image = cv2.imread(str(image_pathname)) 
    input_image = np.resize(
      image, (height, width, 3) 
     ).transpose((2,0,1)).reshape(1, 3, height, width) 
    net.forward_all(data=input_image) 
    segmentation_index = net.blobs[ 
      'argmax' 
     ].data.squeeze().transpose(1,2,0).astype(np.uint8) 
    segmentation = np.empty(segmentation_index.shape, dtype=np.uint8) 
    cv2.LUT(segmentation_index, label_colours, segmentation) 
    prediction_pathname = prediction_directory/image_pathname.name 
    cv2.imwrite(str(prediction_pathname), segmentation) 
0

So che questo è un argomento vecchio, ma che dire:

subkeyword=(Session.query(Subkeyword.subkeyword_id, 
          Subkeyword.subkeyword_word) 
        .filter_by(subkeyword_company_id=self.e_company_id) 
        .filter_by(subkeyword_word=subkeyword_word) 
        .filter_by(subkeyword_active=True) 
        .one()) 

Or

subkeyword=(Session.query(Subkeyword.subkeyword_id, 
          Subkeyword.subkeyword_word) 
        .filter_by(subkeyword_company_id=self.e_company_id) 
        .filter_by(subkeyword_word=subkeyword_word) 
        .filter_by(subkeyword_active=True) 
        .one() 
      )