Python: la suppression d'un attribut de classe dans une sous-classe
J'ai une sous-classe et je veux qu'il pas inclure un attribut de classe qui est présent sur la classe de base.
J'ai essayé ceci, mais ça ne fonctionne pas:
>>> class A(object):
... x = 5
>>> class B(A):
... del x
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
class B(A):
File "<pyshell#1>", line 2, in B
del x
NameError: name 'x' is not defined
Comment puis-je faire cela?
- Cela rompt LSP. Pourquoi voulez-vous faire cela?
- Le
x
variable de classe deB
que vous voulez supprimer est vraiment stockés dansA.__dict__
, donc si vous avez réussi à le supprimer, vous devez également supprimerA.x
. Par conséquent, le plus proche, vous pouvez venir se cacheA.x
en donnantB
unx
variable de classe aussi, comme @Keith suggère dans sa réponse. - Il n'y a pas beaucoup d'une connexion entre les LSP et le typage statique. LSP est un principe sain, car elle rend les hiérarchies de classe un comportement prévisible et cohérente. Ceci s'applique également à statiquement et dynamiquement typés langues, indépendamment de leur fournir les moyens de violer LSP.
Vous devez vous connecter pour publier un commentaire.
Réfléchir sur pourquoi vous voulez faire cela, vous n'avez probablement pas. Envisager de ne pas faire de B hérite de A.
L'idée de sous-classement est de spécialiser un objet. En particulier, les enfants d'une classe devrait être valable pour les instances de la classe parent:
Si vous implémentez ce comportement (par exemple, avec
x = property(lambda: AttributeError)
), vous êtes en rupture le sous-classement concept, et ce qui est Mauvais.Vous pouvez utiliser
delattr(class, field_name)
pour la supprimer de la définition de la classe.Exemple complet:
Vous n'avez pas besoin de le supprimer. Juste le remplacer.
ou tout simplement ne pas le référencer.
Ou envisager une autre conception (instance de l'attribut?).
None
n' pas supprimer cet attribut, qui devrait être assez évident. La suppression d'attributs est ce quedel
etdelattr()
faire. Bhushan's succincte réponse semble être la seule réponse à cette question.Peut-être que vous pouvez fixer des
x
commeproperty
et d'élever AttributeError chaque fois que quelqu'un essaye d'y accéder.AttributeError
serait plus cohérent.Aucune réponse n'avait travaillé pour moi.
Par exemple
delattr(SubClass, "attrname")
(ou son équivalent exact,del SubClass.attrname
) de ne pas "cacher" une méthode parent, parce que ce n'est pas la façon dont la méthode de résolution de travail. Il échouerait avecAttributeError('attrname',)
au lieu de cela, comme la sous-classe n'a pasattrname
. Et, bien sûr, en remplacement de l'attribut avecNone
ne fait pas l'enlever.Considérons cette classe de base:
Je ne connais que deux seuls moyens de la sous-classe en masquant les
expect
attribut:À l'aide d'un descripteur de classe qui soulève
AttributeError
par__get__
. Sur l'attribut de recherche, il y aura une exception, généralement impossible à distinguer d'un échec de la recherche.La façon la plus simple est juste de la déclaration d'une propriété qui soulève
AttributeError
. C'est essentiellement ce que @JBernardo l'a suggéré.Toutefois, cela ne fonctionne que pour les instances, et pas pour les classes (les
hasattr(SpanishInquisition, "expect") == True
affirmation serait cassé).Si vous voulez toutes les affirmations ci-dessus afin de conserver, utiliser ceci:
Je crois que c'est le plus élégant de la méthode, comme le code est clair, générique et compact. Bien sûr, on doit vraiment réfléchir à deux fois si la suppression de l'attribut est ce qu'ils veulent vraiment.
Primordial attribut de recherche avec
__getattribute__
méthode magique. Vous pouvez le faire soit dans une sous-classe (ou un mixin, comme dans l'exemple ci-dessous, que je voulais l'écrire une seule fois), et qui permettrait de masquer l'attribut de la sous-classe instances. Si vous souhaitez masquer la méthode de la sous-classe, vous devez utiliser metaclasses.Cela semble pire (plus détaillé et moins générique) que la méthode ci-dessus, mais on peut considérer cette approche.
Remarque, ce n' pas de travail spécial ("magic") méthodes (par exemple,
__len__
), parce que ceux de dérivation__getproperty__
. Découvrez Méthode Particulière De Recherche section de la documentation Python pour plus de détails. Si c'est ce que vous avez besoin d'annuler, de substituer et appelerobject
's la mise en œuvre, en sautant le parent.Inutile de dire que cela s'applique uniquement à la "nouvelle-classes de style" (ceux qui héritent de
object
), comme la magie des méthodes et descripteur de protocoles ne sont pas pris en charge là. Heureusement, ceux-ci sont une chose du passé.Je suis eu le même problème, et je pensais que j'avais une raison valable pour supprimer l'attribut de classe dans la sous-classe: mon super-classe (appelons Un) a une propriété en lecture seule condition que la valeur de l'attribut, mais dans mon sous-classe (appelons-B), l'attribut de lecture/écriture à une variable d'instance. J'ai trouvé que Python était l'appel de la fonction des biens même si je pensais que la variable d'instance doit avoir été remplaçant. J'aurais pu faire un distinct de lecture de la fonction à utiliser pour accéder à la propriété sous-jacente, mais qui semblait inutile et peu élégante encombrer de l'interface de l'espace de noms (comme si c'est vraiment nécessaire).
Comme il s'avère, la réponse a été de créer un nouveau super-classe abstraite (que l'on appellera S) avec la commune d'origine des attributs de A, A et A et B tirent de S. Depuis Python a duck-typing, il n'a pas vraiment d'importance que B ne s'étendent pas Un, je peux toujours les utiliser dans les mêmes lieux, car ils implicitement implémenter la même interface.
Essaye de faire, c'est probablement une mauvaise idée, mais...
Il ne semble pas être le faire via le "bon" héritage, à cause de la façon dont la recherche jusqu'
B.x
fonctionne par défaut. Lors de la prise enB.x
lax
est d'abord recherché dansB
et si il n'est pas trouvé, il est recherché dansA
, mais d'autre part, lors de la définition ou de la suppression deB.x
seulementB
seront recherchés. Ainsi, par exempleIci, nous voyons que nous avons d'abord ne semble pas être en mesure de supprimer
B.x
car il n'existe pas (A.x
existe et qu'est ce qui est servi lorsque vous évaluezB.x
). Cependant, par la mise enB.x
à 6 leB.x
existent, elles peuvent être récupérées parB.x
et supprimé pardel B.x
par laquelle il cesse d'exister après de nouveauA.x
sera servi en guise de réponse àB.x
.Ce que vous pourrait faire sur l'autre main est d'utiliser des metaclasses de faire
B.x
éleverAttributeError
:Maintenant, bien sûr, les puristes crier que cela rompt avec le LSP, mais il n'est pas simple. Tout dépend si vous considérez que vous avez créé un sous-type en faisant cela. Le
issubclass
etisinstance
méthodes dit oui, mais LSP dit pas (et de nombreux programmeurs suppose "oui" puisque vous héritez deA
).Le LSP signifie que si
B
est un sous-type deA
alors que nous pourrions utiliserB
chaque fois que nous pourrions utiliserA
, mais puisque nous ne pouvons pas faire cela tout en faisant cela, de construire, nous avons pu conclure queB
ce n'est pas un sous-type deA
et donc LSP n'est pas violé.