2017-04-19 1 views
6

Depuis un certain temps, Python a Abstract Base Classes (proposé normalement dans PEP 3119) qui, en particulier pour les types de conteneur, facilite l'écriture de code généralisant les personnalisations les types. Par exemple,Comment faire pour tester des séquences qui ne ressemblent pas à des chaînes en utilisant la bibliothèque standard de Python 3

from collections.abc import Sequence, Set 

if isinstance(x, Sequence): 
    # Handle lists, tuples, or custom objects that behave like lists 
elif isinstance(x, Set): 
    # Handle anything that behaves like a set 

L'un des « trucs » qui me fait trébucher plusieurs fois est que str, bytes et bytearray sont tous considérés comme Sequence s, en plus de plusieurs objets de toute évidence de type liste:

from collections.abc import ByteString, Sequence 

s = 'hello' 
b = b'hello' 
ba = bytearray(b'hello') 
lst = [0, 1, 2] 
t = (0, 1, 2) 

islistlike = lambda x: isinstance(x, Sequence) 

list(map(islistlike, [s, b, ba, lst, t])) # -> [True, True, True, True, True] 

Cela a certainement du sens: généralement ces trois types se comportent comme des listes ou des tuples de caractères (ou octets). Cependant, il semble que ce soit un cas d'utilisation assez commun à poser, cet objet est-il à la fois une liste et non une chaîne de caractères? Le correctif est simple:

islistlike = lambda x: isinstance(x, Sequence) and not isinstance(x, (str, ByteString)) 

list(map(islistlike, [s, b, ba, lst, t])) # -> [False, False, False, True, True] 

Mais cela semble que ce serait un modèle assez commun que je me demande si je me manque quelque chose dans la bibliothèque standard.

  • Y at-il abc dans la bibliothèque standard de Python tels que islistlike = lambda x: isinstance(x, abc) se comporte comme le dernier exemple ci-dessus?
  • Existe-t-il une discussion de conception autour de Sequence vs des conteneurs semblables à des chaînes quelque part? (Je ne l'ai pas trouvé quoi que ce soit lié à cela dans la documentation de la bibliothèque standard ou PEP 3119.)
+0

1. Pas aussi loin que je sache. 2. Comme vous le constatez, les * "conteneurs ressemblant à des chaînes" * * sont des * séquences, des chaînes/octets à caractère unique ('ByteString' hérite de' Sequence', même), donc * "vs" * ne fait pas vraiment sens. Dans de nombreux cas, une chaîne serait considérée comme un argument parfaitement valide pour une fonction ou une méthode qui prend une séquence, vous devrez donc être explicite lorsque ce n'est pas le cas. – jonrsharpe

+0

@jonrsharpe merci pour les commentaires! Je dirais que "* vs *" pourrait être approprié, selon la situation. Souvent, je pense aux chaînes de caractères (octets, etc.) comme des points de données atomiques uniques, et je veux savoir, ai-je affaire à un conteneur semblable à une liste d'éléments de type chaîne, ou ai-je affaire à une seule chaîne? article. Un exemple de cela est l'utilisation d'une fonction récursive pour aplatir un dictionnaire imbriqué, par exemple - dans la fonction récursive que vous souhaitez distribuer sur le type de l'élément. – DGrady

Répondre

1

Non, il n'y a rien dans la bibliothèque standard pour distinguer facilement entre str et bytes -comme séquences vs autres types de séquence. Si cela est courant dans votre base de code, alors vous voudrez peut-être rouler le vôtre.