Quel est le but de vérifier self.__class__
? J'ai trouvé du code qui crée une classe d'interface abstraite et vérifie ensuite si son self.__class__
est lui-même, par exemple.
class abstract1 (object):
def __init__(self):
if self.__class__ == abstract1:
raise NotImplementedError("Interfaces can't be instantiated")
Quel est le but de cela? Est-ce pour vérifier si la classe est un type d'elle-même?
Le code provient de NLTK http://nltk.googlecode.com/svn/trunk/doc/api/nltk.probability-pysrc.html#ProbDistI
self.__class__
Est une référence au type de l'instance actuelle.
Pour les instances de abstract1
, Ce serait la classe abstract1
elle-même , ce que vous ne voulez pas avec une classe abstraite. Les classes abstraites sont uniquement destinées à être sous-classées, pas à créer directement des instances:
>>> abstract1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
NotImplementedError: Interfaces can't be instantiated
Pour une instance d'une sous-classe de abstract1
, self.__class__
Serait une référence à la sous-classe spécifique:
>>> class Foo(abstract1): pass
...
>>> f = Foo()
>>> f.__class__
<class '__main__.Foo'>
>>> f.__class__ is Foo
True
Lancer une exception ici, c'est comme utiliser une instruction assert
ailleurs dans votre code, cela vous protège contre les erreurs idiotes.
Notez que la méthode Pythonic pour tester le type d'une instance consiste à utiliser la fonction type()
à la place, avec un test d'identité avec l'opérateur is
:
class abstract1(object):
def __init__(self):
if type(self) is abstract1:
raise NotImplementedError("Interfaces can't be instantiated")
type()
doit être préféré à self.__class__
car ce dernier peut être masqué par un attribut de classe .
Il n'y a aucun intérêt à utiliser un test d'égalité ici comme pour les classes personnalisées, __eq__
Est de toute façon implémenté comme un test d'identité.
Python comprend également une bibliothèque standard pour définir des classes de base abstraites, appelée abc
. Il vous permet de marquer des méthodes et des propriétés comme abstraites et refusera de créer des instances de toute sous-classe qui n'a pas encore redéfini ces noms.
Le code que vous avez affiché là-bas est un no-op; self.__class__ == c1
ne fait pas partie d'un conditionnel donc le booléen est évalué mais rien n'est fait avec le résultat.
Vous pouvez essayer de créer une classe de base abstraite qui vérifie si self.__class__
est égal à la classe abstraite par opposition à un enfant hypothétique (via une instruction if), afin d'empêcher l'instanciation de la classe de base abstraite elle-même en raison d'une erreur de développeur.
Je dirais que certains feraient:
class Foo(AbstractBase):
def __init__(self):
super(Foo, self).__init__()
# ...
Même lorsque la base est abstraite, vous ne voudriez pas que la base __init__
pour lancer NotImplementedError
. Hé, peut-être que ça fait même quelque chose d'utile?
Quel est le but de cela? Est-ce pour vérifier si la classe est un type d'elle-même?
Oui, si vous essayez de construire un objet de type Abstract1
cela va lever cette exception vous disant que vous n'êtes pas autorisé à le faire.
Dans Python 3 soit en utilisant type()
pour vérifier le type ou __class__
renverra le même résultat.
class C:pass
ci=C()
print(type(ci)) #<class '__main__.C'>
print(ci.__class__) #<class '__main__.C'>
J'ai récemment vérifié le implémentation pour le @dataclass
décorateur (Raymond Hettinger est directement impliqué dans ce projet), et ils utilisent __class__
pour faire référence au type.
Il n'est donc pas faux d'utiliser __class__
:)
Les indices se trouvent au nom de la classe, "abstract1", et dans l'erreur. Il s'agit d'une classe abstraite, c'est-à-dire d'une classe destinée à être sous-classée. Chaque sous-classe fournira son propre comportement. La classe abstraite elle-même sert à documenter l'interface, c'est-à-dire les méthodes et les arguments que les classes implémentant l'interface devraient avoir. Il n'est pas censé être instancié lui-même, et le test est utilisé pour dire si nous sommes dans la classe elle-même ou dans une sous-classe.
Voir la section sur les classes abstraites dans ce article par Julien Danjou.