2015-02-04 5 views
15

Ho notato che l'aggiunta di uno spazio a stringhe identiche li rende confrontabili ineguali usando is, mentre le versioni non spaziali sono uguali.Perché uno spazio influisce sul confronto delle identità di stringhe uguali?

a = 'abc' 
b = 'abc' 
a is b 
#outputs: True 

a = 'abc abc' 
b = 'abc abc' 
a is b 
#outputs: False 

Ho letto this question about comparing strings with == and is. Penso che questa sia una domanda diversa perché il carattere dello spazio sta cambiando il comportamento, non la lunghezza della stringa. Vedi:

a = 'abc' 
b = 'abc' 
a is b # True 

a = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah' 
b = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah' 
a is b # True 

Perché l'aggiunta di uno spazio alla stringa modifica il risultato di questo confronto?

+1

Questa domanda è formulata in modo diverso, ma le risposte alle altre domande funzionano qui, poiché la chiave sta riconoscendo cosa fa 'is' e come differisce da' == '. – DSM

+1

C'è stato un commento che è stato cancellato facendo riferimento alla differenza tra "è" e "==". È questo il tuo problema, o sei curioso di sapere perché le stringhe hanno la stessa identità se non c'è spazio, ma hanno identità diverse quando c'è un carattere spaziale ... Altri caratteri non stampabili rendono anche le identità diverse. – hft

+2

Ho chiesto NULLA come == o la differenza tra == ed è, sry – midkin

risposta

30

L'interprete Python memorizza alcune stringhe in base a determinati criteri, la prima stringa abc viene memorizzata nella cache e utilizzata per entrambi, mentre la seconda non lo è. Lo stesso vale per i piccoli interi da -5 a 256.

Poiché le stringhe sono internati/assegnazione di cache a e b-"abc" rende a e b punto agli stessi oggetti in memoria in modo da utilizzare is, che verifica se due oggetti sono in realtà lo stesso oggetto, restituisce True.

La seconda stringa abc abc non viene memorizzata nella cache in modo che siano due oggetti completamente diverso in memoria controllo d'identità in modo utilizzando is rendimenti False. Questa volta a è nonb. Entrambi puntano a oggetti diversi nella memoria.

In [43]: a = "abc" # python caches abc 
In [44]: b = "abc" # it reuses the object when assigning to b 
In [45]: id(a) 
Out[45]: 139806825858808 # same id's, same object in memory 
In [46]: id(b) 
Out[46]: 139806825858808  
In [47]: a = 'abc abc' # not cached 
In [48]: id(a) 
Out[48]: 139806688800984  
In [49]: b = 'abc abc'  
In [50]: id(b)   # different id's different objects 
Out[50]: 139806688801208 

I criteri per le stringhe di caching è se la stringa ha solo lettere, underscores e numeri nella stringa Quindi nel tuo caso lo spazio non soddisfa i criteri.

Utilizzando l'interprete esiste un caso in cui si può finire per puntare allo stesso oggetto anche quando la stringa non soddisfa i criteri di cui sopra, più assegnazioni.

In [51]: a,b = 'abc abc','abc abc' 

In [52]: id(a) 
Out[52]: 139806688801768 

In [53]: id(b) 
Out[53]: 139806688801768 

In [54]: a is b 
Out[54]: True 

Guardando codeobject.c source per decidere i criteri che vediamo NAME_CHARS decide che cosa può essere internato:

#define NAME_CHARS \ 
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 

/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */ 

static int 
all_name_chars(unsigned char *s) 
{ 
    static char ok_name_char[256]; 
    static unsigned char *name_chars = (unsigned char *)NAME_CHARS; 

    if (ok_name_char[*name_chars] == 0) { 
     unsigned char *p; 
     for (p = name_chars; *p; p++) 
      ok_name_char[*p] = 1; 
    } 
    while (*s) { 
     if (ok_name_char[*s++] == 0) 
      return 0; 
    } 
    return 1; 
} 

una stringa di lunghezza 0 o 1 sarà sempre condivisa come si può vedere nella funzione PyString_FromStringAndSize nel stringobject.c origine.

/* share short strings */ 
    if (size == 0) { 
     PyObject *t = (PyObject *)op; 
     PyString_InternInPlace(&t); 
     op = (PyStringObject *)t; 
     nullstring = op; 
     Py_INCREF(op); 
    } else if (size == 1 && str != NULL) { 
     PyObject *t = (PyObject *)op; 
     PyString_InternInPlace(&t); 
     op = (PyStringObject *)t; 
     characters[*str & UCHAR_MAX] = op; 
     Py_INCREF(op); 
    } 
    return (PyObject *) op; 
} 

Non direttamente legati alla domanda, ma per chi fosse interessato PyCode_New anche dalla fonte codeobject.c mostra come più stringhe sono internati quando si costruisce una codeobject una volta le corde soddisfino i criteri in all_name_chars.

PyCodeObject * 
PyCode_New(int argcount, int nlocals, int stacksize, int flags, 
     PyObject *code, PyObject *consts, PyObject *names, 
     PyObject *varnames, PyObject *freevars, PyObject *cellvars, 
     PyObject *filename, PyObject *name, int firstlineno, 
     PyObject *lnotab) 
{ 
    PyCodeObject *co; 
    Py_ssize_t i; 
    /* Check argument types */ 
    if (argcount < 0 || nlocals < 0 || 
     code == NULL || 
     consts == NULL || !PyTuple_Check(consts) || 
     names == NULL || !PyTuple_Check(names) || 
     varnames == NULL || !PyTuple_Check(varnames) || 
     freevars == NULL || !PyTuple_Check(freevars) || 
     cellvars == NULL || !PyTuple_Check(cellvars) || 
     name == NULL || !PyString_Check(name) || 
     filename == NULL || !PyString_Check(filename) || 
     lnotab == NULL || !PyString_Check(lnotab) || 
     !PyObject_CheckReadBuffer(code)) { 
     PyErr_BadInternalCall(); 
     return NULL; 
    } 
    intern_strings(names); 
    intern_strings(varnames); 
    intern_strings(freevars); 
    intern_strings(cellvars); 
    /* Intern selected string constants */ 
    for (i = PyTuple_Size(consts); --i >= 0;) { 
     PyObject *v = PyTuple_GetItem(consts, i); 
     if (!PyString_Check(v)) 
      continue; 
     if (!all_name_chars((unsigned char *)PyString_AS_STRING(v))) 
      continue; 
     PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); 
    } 

Questa risposta si basa su semplici compiti utilizzando l'interprete CPython, per quanto riguarda l'internamento in relazione a funzioni o qualsiasi altra funzionalità al di fuori di semplici compiti, che non è stato chiesto nemmeno risposto.

Se qualcuno con una maggiore comprensione del codice c ha qualcosa da aggiungere sentitevi liberi di modificare.

C'è una spiegazione molto più approfondita here dell'intera stringa interning.

+1

Il tuo diritto sui numeri come a = 260, b = 260 ---> a è b è Falso ... Comunque qual è la risposta riguardo le mie corde? – midkin

+1

No dato che a = 'rgaerdavaerdgvrdversdvseDvaerdvreds', b = rgaerdavaerdgvrdversdvseDvaerdvreds è True .. si tratta dello spazio CHAR e non di quello lungo o piccolo – midkin

+2

Nota: la domanda dupa ** contiene ** le informazioni che stai dando qui, nel [secondo risposta] (http://stackoverflow.com/a/1504848/510937). – Bakuriu

Problemi correlati