0
votes

La classe de string mutable python ne fonctionne pas correctement

J'ai créé une classe de cordes mutable en Python, basée sur la classe intégrée str code> STR.

Je peux changer le premier caractère, mais lorsque j'appelle capitaliser () Code> , il utilise la valeur ancienne à la place p> xxx pré>

Sortie attendue: strong> p>

hello world

Cello world


0 commentaires

3 Réponses :


1
votes

Votre implémentation hérite de str , de sorte qu'il apporte toutes les méthodes str . Cependant, la mise en œuvre de la méthode str.capitalize () n'est pas conçue pour le prendre en compte. Méthodes telles que str.capitalize () renvoyer un nouvel STR objet avec le changement requis appliqué.

De plus, les types intégrés Python Ne rangez pas leur état dans un __ dict __ dict __ cartographie des attributs, mais utilisez interne structure structures de données ) uniquement accessible sur le niveau C; Votre attribut auto-self.string n'est pas l'endroit où le (équivalent C de) str .__ nouveau __ () stocke les données de chaîne. Le str.capitalize () La méthode basse sa valeur de retour sur la valeur stockée dans la structure de données interne lorsque l'instance a été créée, qui ne peut pas être modifiée à partir du code Python.

Vous devrez ombrager toutes les méthodes str qui renvoient une nouvelle valeur, y compris str.capitalize () pour se comporter différemment. Si vous souhaitez que ces méthodes de renvoient une nouvelle instance pour modifier la valeur en place, vous devez le faire vous-même: xxx

qui peut être beaucoup de travail, des méthodes d'écriture Comme ceux-ci pour chaque méthode possible str qui renvoie une valeur mise à jour. Au lieu de cela, vous pouvez utiliser un __ getattribute __ crochet à des méthodes de redirection: xxx

démo avec le __ getattribute __ méthode ci-dessus ajoutée à votre Classe: xxx

un côté REMARQUE: le __ RECR __ doit utiliser REC () pour renvoyer une représentation appropriée, non juste la valeur: xxx

également, prenez en compte la plupart des API Python codées dans C et prennent une valeur str comme entrée, sont probables. Pour utiliser le API C pour Strings Unicode et ainsi Non seulement ignorer complètement vos implémentations personnalisées, mais comme l'original str.capitalize () Ignorera également l'attribut auto-self.string . Au lieu de cela, ils interagiront également avec les données internes str .


13 commentaires

Compte tenu de tout cela, y a-t-il des avantages gagnés par cette classe héritante de str ?


@Khelwood: Ça va tester comme une chaîne n'importe où isinstance (objet, str) est utilisé. Étant donné qu'il n'y a pas de type collections.abc que vous pouvez utiliser à la place, c'est une raison décente de continuer à le faire.


Cela ne sera-t-il pas plutôt trompeur?


@khelwood: Cela dépend de ce que la puissance espère utiliser cette classe.


@khelwood: Et en programmation, il n'y a pas de «trompeur», c'est ce que l'héritage est tout à propos de! Étendre et modifier le comportement mais être toujours compatible avec l'interface de la classe mère.


"Compatible" dans le sens d'avoir un tas de méthodes qui ressemblent aux méthodes que vous attendez, mais faites quelque chose de très différent ...


Y a-t-il un moyen d'obtenir toutes les méthodes de str ? De cette façon, je peux en faire la boucle et les redéfinir à l'aide d'une lambda ou autre chose


@khelwood: oui, alors? C'est comme ça que beaucoup d'objets fonctionnent. Liste , tuple , octets et str sont toutes des séquences, de même que de nombreuses méthodes communes. Cependant, leurs implémentations sont très différentes pour tout ce que les noms de méthode et les signatures sont les mêmes.


@Michaelfish: utilisez vars (str) pour obtenir un dictionnaire de tous les attributs que le type définit. Les méthodes ne sont que des attributs qui se produisent sont appelables (et d'habitude, mettre en œuvre le protocole descripteur). Prendre en compte il y a au moins une méthode statique sur le type, str.maketrans () .


@Michaelfish: Il existe également des méthodes qui renvoient autre chose qu'un str , tel que des tests qui renvoient un booléen ( __ contient __ () , ispper () , isdigit () , startswith () , etc.) ou renvoyer une liste ou un tuple ( divisé () , partition () , rsplit () , rPartition () , etc.). Il n'y a pas d'approche à une taille unique - toutes les approches ici, je crains.


Je suppose que votre "qui dépend de ce que la puissance espère utiliser cette classe pour" couvre ce motif, mais mon objection est que si j'ai une fonction qui accepte une chaîne comme argument (et je confirme qu'il s'agit d'un str avec isinstance ), alors je m'attends à pouvoir appeler y = x.capitaliser () etc. et obtenir les résultats prescrits par l'habituel < code> str méthodes. Avoir quelque chose déguisé en tant que STR comportant un comportement totalement différent semble être un excellent moyen d'introduire des comportements étranges et de déranger les bugs dans votre programme.


Et si l'utilisation prévue de l'OP est pas incluent la transmission de leurs chaînes mutables dans des fonctions qui attendent des chaînes normales, alors pourquoi devrait-il être souhaitable d'avoir isinstance (objet, str) retourner vrai?


@khelwood: Concaténation avec d'autres STR Les valeurs où string () est la valeur de droite. Pour a + b , où b est une sous-classe de type (a) , b .__ radd __ () est appelé avant a .__ ajouter __ () . Ceci est spécifiquement afin que vous puissiez remplacer de telles surcharges de l'opérateur dans une sous-classe.



0
votes

vous hérité str de Capitalize , qui ignore les comportements de votre classe et utilise simplement les données sous-jacentes du "vrai" str .

hériter d'un type intégré comme celui-ci nécessite efficacement de réimplément chaque méthode ou de faire des métaprogramming avec __ getattribute __ ; Sinon, les comportements de type sous-jacent seront hérités non modifiés.


0 commentaires

0
votes

Cette approche est inférieure aux réponses déjà suggérées. Il y a plus de frais généraux car vous ne pouvez pas simplement suivre les choses comme une liste, et isinstance (s, str) ne fonctionnera pas, par exemple.

Une autre façon d'accomplir cela est de Sous-classe Collections.Userstring . C'est une enveloppe autour du type de chaîne intégré qui le stocke en tant que membre nommé données . Donc, vous pouvez faire quelque chose comme xxx

, puis vous obtiendrez capitaliser et les autres méthodes de chaîne gratuites.


0 commentaires