2015-04-18 7 views
5

Come attualmente in discussione in this question, sto scrivendo versioni incluse delle funzioni integrate range e xrange. Se questi sono collocati all'interno di un modulo di nome inclusive, vedo due possibili modi di nominare le funzioni stesse:È corretto riutilizzare i nomi delle funzioni built-in di Python?

  1. Nome le funzioni inclusive_range e inclusive_xrange modo che il codice cliente li può utilizzare come segue:

    from inclusive import * 
    ... 
    inclusive_range(...) 
    
  2. Nome le funzioni range e xrange:

    import inclusive 
    ... 
    inclusive.range(...) 
    

Per me, il secondo esempio di codice client sembra migliore, ma dovrei evitare di riutilizzare i nomi incorporati in questo modo?

+0

Buona domanda. Il primo esempio non è buono. Se dovessi evitare di usare gli stessi nomi, li chiamerei 'inclusive.irange()' e 'inclusive.ixrange()'. Ma forse usando 'range()' e 'xrange()' è OK. – wrgrs

risposta

4

Questo è diventato un po 'un elenco di opzioni diverse, piuttosto che una risposta diretta. Tuttavia, due concetti sono di primaria importanza:

  • Gli utenti dovrebbero essere in grado di sostituire range e xrangese esplicitamente scelgono di; ma
  • Gli utenti non dovrebbero essere in grado di sostituire implicitamente/accidentalmenterange e xrange;

dovrebbe sempre essere chiaro ai lettori del loro codice in cui vengono utilizzati i built-in e dove vengono utilizzate le sostituzioni.

Per questo motivo, tutte le opzioni che ho delineato sotto impediscono l'importazione da di caratteri jolly (from inclusive import *) dallo shadowing dei built-in.Qual è l'opzione migliore per te dipende se vedi la sostituzione dei built-in come uso primario o secondario del tuo modulo. Gli utenti generalmente vogliono sostituire i built-in o usarli l'uno accanto all'altro?


Nella tua posizione, penso che vorrei fare quanto segue:

inclusive.py:

"""Inclusive versions of range and xrange.""" 

__all__ = [] # block 'from inclusive import *' 

old_range, old_xrange = range, xrange # alias for access 

def range(...): # shadow the built-in 
    ... 

def xrange(...): # ditto 
    ... 

Questo permette agli utenti di entrambi:

  1. import inclusive e accesso inclusive.range e inclusive.xrange ;
  2. from inclusive import range, xrange, che sostituisce chiaramente il built-in senza spiacevoli effetti collaterali; oppure
  3. from inclusive import range as irange, xrange as ixrange per utilizzare le versioni integrata e di sostituzione l'una accanto all'altra.

Definire __all__ come una lista vuota significa che from inclusive import *non sarà tranquillamente ombra le built-in.


Se davvero voleva, si potrebbe aggiungere:

irange, ixrange = range, xrange 

alla fine del inclusive.py e modificare la definizione __all__ a:

__all__ = ['irange', 'ixrange'] 

Ora gli utenti hanno due opzioni aggiuntive:

  • from inclusive import irange, ixrange (leggermente più semplice dell'aliasing manuale delle funzioni come nell'opzione 3 sopra); e
  • from inclusive import * (stesso risultato come sopra, ancora nessuna ombreggiatura implicita di built-in).

Naturalmente, si potrebbe andare completamente nella direzione opposta - nominare le proprie versioni irange e ixrange, quindi se l'utente vuole davvero per sostituire i built-in avrebbero dovuto:

from inclusive import irange as range, ixrange as xrange 

Questo non richiede di definire __all__ per evitare un'importazione di caratteri jolly che ombreggia i built-in.

+1

Potrebbe anche essere utile ricordare che è sempre possibile recuperare le funzioni originali 'range' e' xrange' da '__builtins__' usando' __builtins __. Range' e '__builtins __. Xrange'. –

+0

Grazie per la risposta dettagliata, in particolare per i due concetti citati in alto, sono certamente appropriati. Apprezzo anche l'elenco dei possibili modi per raggiungere questi concetti, anche se devo ancora decidere esattamente quale opzione usare. – user200783

+0

Per quanto riguarda "Gli utenti in genere vogliono sostituire i built-in, o usarli uno accanto all'altro?". Mi aspetto che la sostituzione dei built-in potrebbe facilmente essere fonte di confusione, quindi non aspettatevi che sia un caso di uso comune. – user200783

0

Si dovrebbe evitare di riutilizzare i nomi di funzione incorporati in questo modo, poiché ciò può interrompere tutte le librerie a cui si sta dipendendo ed è molto confuso per le altre persone (o in futuro) da leggere e gestire. Tuttavia, se necessario, l'opzione per farlo è disponibile.

+1

* "questo può infrangere qualsiasi libreria che stai dipendendo da" * - Python sta attento a ** not ** lasciare che questo accada, la sostituzione dei built-in sarebbe ** ** solo nello scopo di 'inclusive' a meno che l'utente non decida diversamente. – jonrsharpe

+0

Sì, ma se si esegue "from inclusive import *", ciò può sicuramente accadere. –

+0

Solo nel modulo in cui viene effettuata l'importazione, ed è per questo che le importazioni di caratteri jolly sono scoraggiate - vedere la mia risposta per le opzioni per evitare che ciò accada (pur continuando a fornire l'opzione per ** esplicitamente ** sostituire 'range' e' xrange '). – jonrsharpe

0

È possibile, ma probabilmente non è una buona idea.

Il problema è che se qualcun altro utilizza la libreria si possono introdurre effetti collaterali

from your_lib import inclusive range 

..... lots of code ..... 

range() # ambiguous 
+1

Questo non è affatto ambiguo - 'range' è ancora il built-in, la versione inclusiva è' inclusive.range'. Diventa un problema solo se l'utente fa 'da your_lib.inclusive import * 'o' da your_lib.inclusive range di importazione, xrange' (nel qual caso probabilmente * vogliono ** sostituire i built-in). – jonrsharpe

+0

scusa il tuo diritto - Ho cambiato la mia risposta per mostrare l'importazione che potrebbe essere un problema se l'importazione è in alto e l'intervallo è utilizzato in profondità nel codice. Non è un grosso problema, ma è ancora una potenziale trappola quando non ha davvero bisogno di essere – acutesoftware

0

Il problema qui è che all'interno del modulo che non sarebbe in grado di chiamare il builtin range() o xrange(). Il modo in cui descrivi inclusive.range() sembra buono, ma gli altri utenti potrebbero non importare nello stesso modo e otterrebbero anche dei conflitti.

Che dire di inclusive.irange() e inclusive.ixrange()?

Modifica: è vero che potresti utilizzare range() nel tuo modulo se hai avuto cura di importarli e rinominarli, ma questo è probabilmente un altro segno che questo è un modo potenzialmente complicato.

+0

Tu * sarebbe * ancora in grado di usarli, ma dovresti farli alias prima delle definizioni delle funzioni (es. 'Old_range = range; def range (...): '). – jonrsharpe

+0

Sì, è vero. Ho modificato per rendere chiaro. Grazie. – wrgrs

Problemi correlati