Ceci est un excellent exemple de la raison pour laquelle les __dunder__méthodes ne devraient pas être utilisées directement car elles ne sont souvent pas des remplacements appropriés pour leurs opérateurs équivalents; vous devriez utiliser l' ==opérateur à la place pour les comparaisons d'égalité, ou dans ce cas particulier, lors de la vérification None, utilisez is(passez au bas de la réponse pour plus d'informations).
Tu as fait 
None.__eq__('a')
# NotImplemented
Quels retours NotImplementedpuisque les types comparés sont différents. Prenons un autre exemple où deux objets de types différents sont comparés de cette manière, tels que 1et 'a'. Faire (1).__eq__('a')n'est pas non plus correct et reviendra NotImplemented. La bonne façon de comparer ces deux valeurs pour l'égalité serait  
1 == 'a'
# False
Ce qui se passe ici est
- Tout d'abord, (1).__eq__('a')est essayé, qui revientNotImplemented. Cela indique que l'opération n'est pas prise en charge, donc
- 'a'.__eq__(1)est appelé, qui renvoie également le même- NotImplemented. Alors,
- Les objets sont traités comme s'ils n'étaient pas identiques et Falsesont renvoyés.
Voici un joli petit MCVE utilisant des classes personnalisées pour illustrer comment cela se produit:
class A:
    def __eq__(self, other):
        print('A.__eq__')
        return NotImplemented
class B:
    def __eq__(self, other):
        print('B.__eq__')
        return NotImplemented
class C:
    def __eq__(self, other):
        print('C.__eq__')
        return True
a = A()
b = B()
c = C()
print(a == b)
# A.__eq__
# B.__eq__
# False
print(a == c)
# A.__eq__
# C.__eq__
# True
print(c == a)
# C.__eq__
# True
Bien sûr, cela n'explique pas pourquoi l'opération retourne true. C'est parce que NotImplementedc'est en fait une valeur de vérité:
bool(None.__eq__("a"))
# True
Pareil que,
bool(NotImplemented)
# True
Pour plus d'informations sur les valeurs considérées comme véridiques et fausses, consultez la section de documentation sur le test de la valeur de vérité , ainsi que cette réponse . Il est intéressant de noter ici que NotImplementedc'est vrai, mais cela aurait été une histoire différente si la classe avait défini une méthode __bool__ou __len__qui retournait Falseou 0respectivement.
Si vous voulez l'équivalent fonctionnel de l' ==opérateur, utilisez operator.eq:
import operator
operator.eq(1, 'a')
# False
Cependant, comme mentionné précédemment, pour ce scénario spécifique , dans lequel vous recherchez None, utilisez is:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
L'équivalent fonctionnel de ceci utilise operator.is_:
operator.is_(var2, None)
# True
Noneest un objet spécial, et une seule version existe en mémoire à tout moment. IOW, c'est le seul singleton de la NoneTypeclasse (mais le même objet peut avoir n'importe quel nombre de références). Les directives PEP8 expliquent cela:
  Les comparaisons avec des singletons comme Nonedevraient toujours être faites avec isou
   is not, jamais avec les opérateurs d'égalité.
En résumé, pour les singletons aiment None, une vérification de référence avec isest plus approprié, même si les deux ==et isfonctionnera très bien.