2014-10-23 4 views
8

Il metodo usuale di accesso agli attributi richiede che i nomi degli attributi siano valid python identifiers.Attributi che non sono identificatori Python validi

Ma attributi non devono essere validi identificatori Python:

>>> class Thing: 
...  def __init__(self): 
...   setattr(self, '0potato', 123) 
...   
>>> t = Thing() 
>>> Thing.__getattribute__(t, '0potato') 
123 
>>> getattr(t, '0potato') 
123 

Naturalmente, t.0potato rimane un SyntaxError, ma l'attributo c'è comunque:

>>> vars(t) 
{'0potato': 123} 

Qual è la ragione per questo è ammissibile? Esiste davvero un caso d'uso valido per gli attributi con spazi, stringa vuota, parole chiave riservate a Python ecc.? Ho pensato che il motivo era che gli attributi erano solo le chiavi del dict oggetto/spazio dei nomi, ma questo non ha senso, perché gli altri oggetti che sono le chiavi dict valide non sono consentiti:

>>> setattr(t, ('tuple',), 321) 
TypeError: attribute name must be string, not 'tuple' 
+2

La risposta al motivo per cui questo è consentito può essere trovata nella risposta di @ poke [qui] (http://stackoverflow.com/a/25477703/2555451).Non credo che la tua domanda debba essere duplice, tuttavia, perché richiede casi di uso legittimo laddove l'altro si chiede solo perché questo sia permesso. – iCodez

+0

Per iniziare vedi la risposta di Martin v. Löwis in [numero di Python 14029] (http://bugs.python.org/issue14029). Quindi dipende principalmente dall'implementazione sottostante di '__setattr__' che può accettare non identificatori. Tuttavia, sebbene sia possibile creare un '__setattr__' che accetta le tuple, ma fallisce ancora quando viene chiamato tramite' setattr'. Quindi sembra che il metodo incorporato non si limiti a dare ciecamente i suoi argomenti al metodo '__setattr__' dell'oggetto. –

+4

Ecco [Guido van Rossum considerando] (https://mail.python.org/pipermail/python-dev/2012-March/117441.html) la tua domanda. –

risposta

0

I dettagli da un comment sul inserisco pienamente rispondere a questa domanda, quindi sto postando come una risposta:

Guido dice:

... si tratta di una caratteristica che è possibile utilizzare qualsiasi stringa arbitraria con getattr() e setattr(). Tuttavia queste funzioni dovrebbero (e fare!) rifiutare le stringhe.

Possibili casi d'uso includono l'occultamento di attributi dall'accesso puntato regolare e la creazione di attributi in corrispondenza di origini dati esterne (che possono essere in conflitto con le parole chiave Python). Quindi, l'argomento sembra essere semplicemente non c'è una buona ragione per proibirlo.

Per quanto riguarda un motivo per non consentire i non-stringhe, questa sembra essere una restrizione sensibile che è garantire maggiori prestazioni della realizzazione:

Anche se dicts di Python hanno già alcune ottimizzazioni stringa solo - hanno appena adattarsi dinamicamente ad un approccio più generico e leggermente più lento una volta che viene visualizzata la prima stringa non chiave.

1

Quindi, per rispondere alla domanda dei casi d'uso, osservando il ragionamento alla base del funzionamento di Python nei riferimenti dei commenti precedenti, possiamo dedurre alcune delle situazioni che potrebbero rendere utile questa stranezza di Pythonic.

  1. Si desidera che a un oggetto sia assegnato un attributo a cui non è possibile accedere con la notazione dei punti, ad esempio per proteggerlo dall'utente ingenuo. (Citando Guido: "alcune persone potrebbero usarlo per nascondere lo stato che non vogliono essere accessibili usando la notazione regolare degli attributi (x.foo)". Naturalmente, continua a dire, "ma mi sembra un abuso dello spazio dei nomi per me e ci sono molti altri modi per gestire tale stato . ")
  2. Si desidera che i nomi di attributo di un oggetto corrispondano a dati esterni su cui non si ha alcun controllo. Pertanto, è necessario essere in grado di utilizzare qualsiasi stringhe appare nei dati esterni come nome di attributo, anche se corrisponde a una parola riservata Python o contiene spazi incorporati o trattini, ecc