Per rispondere a questa domanda dobbiamo immergerci un po 'nei dettagli di come funziona l'interprete python. Potrebbe essere diverso in altre implementazioni Python.
Iniziamo innanzitutto da dove sono definite le funzioni os.remove
e os.unlink
. In Modules/posixmodule.c sono registrati come:
{"unlink", posix_unlink, METH_VARARGS, posix_unlink__doc__},
{"remove", posix_unlink, METH_VARARGS, posix_remove__doc__},
Nota che i puntatori a funzione sia punto di posix_unlink
nella loro ml_meth
membro.
Per gli oggetti metodo, l'operatore di uguaglianza ==
è implementato da in Objects/methodobject.c.
Contiene questa logica, che spiega perché l'operatore ==
restituisce True
.
a = (PyCFunctionObject *)self;
b = (PyCFunctionObject *)other;
eq = a->m_self == b->m_self;
if (eq)
eq = a->m_ml->ml_meth == b->m_ml->ml_meth;
Per le funzioni incorporate m_self
è NULL
così eq
inizia true
. Quindi confrontiamo i puntatori di funzione in ml_meth
(lo stesso posix_unlink
a cui si fa riferimento dalla struttura in alto) e poiché corrispondono a eq
rimane true
. Il risultato finale è che python restituisce True
.
L'operatore is
è più semplice e più rigido. L'operatore is
confronta solo i puntatori PyCFunctionObj*
. Saranno diversi: provengono da diverse strutture e sono oggetti distinti, pertanto l'operatore is
restituirà False
.
La logica è probabile che siano oggetti di funzioni separate (richiamare le loro docstring sono diversi) ma indicano la stessa implementazione, quindi la differenza di comportamento tra is
e ==
è giustificabile.
is
porta una garanzia più forte, ed è pensato per essere veloce ed economico (un confronto puntatore, in sostanza). L'operatore ==
ispeziona l'oggetto e restituisce True
quando il suo contenuto corrisponde. In questo contesto, il puntatore della funzione è il contenuto.