Je ne comprends pas pourquoi .items () renvoie un résultat différent de .viewitems () lors de la comparaison de deux dictionnaires sous forme de liste.
# python 2.7
d1 = {'1': '10', '2': '20'} # two key-value pairs
d2 = {'3': '30', '4': '40', '5': '50'} # three key-value pairs
print d1 <= d2 # True
print d1.items() <= d2.items() # True
print d1.viewitems() <= d2.viewitems() # False
print d1.items() # [('1', '10'), ('2', '20')]
print d1.viewitems() # dict_items([('1', '10'), ('2', '20')])
Cela semble être la principale différence entre .items ( ) et .viewitems () est que .items () renvoie une liste et viewitems () renvoie un truc dict_items.
Est-il recommandé d'utiliser simplement d1
Aussi, comment rendre cela compatible avec Python 3?
3 Réponses :
Votre objectif déclaré est de comparer les tailles de dictionnaires ... ce que vous n'avez pas fait du tout. Vous devez utiliser len pour cela.
Ce que vous avez fait, c'est de comparer des éléments de deux types très différents. items renvoie une liste de tuples, qui sont facilement comparés par les algorithmes bien connus: vérifiez les éléments dans l'ordre donné pour la valeur relative. La comparaison de tuple est familière à la plupart d'entre nous.
Cependant, un dict_view est un objet de vue dynamique, pas une simple liste de valeurs. Vous comparez un objet plus complexe, pas simplement une liste évidente de valeurs. La définition de l'ordre et de la comparaison ne sont pas facilement visibles pour nous, simples mortels.
La définition de classement et de comparaison est visible; la définition des objets de vue dict spécifie qu'ils implémentent l'ABC collections.abc.Set , et alors que l'ABC lui-même ne dit pas réellement ce que __le__ / < = devrait faire, tout réalisateur raisonnable suivrait les règles que set suit, à savoir, renvoyer True si le côté gauche est un sous-ensemble de, ou égal à , le côté droit.
d1.viewitems() <= d2.viewitems() # False
Attendez, donc les résultats Vrai et Faux sont-ils fiables? Nous migrons de python 2 vers 3, et un linter a remplacé viewitems () par items (), puis a provoqué l'échec d'un test unitaire. Si .items () et .viewitems () font quelque chose de différent que de simplement comparer les tailles de dictionnaires, que dois-je faire?
Cela dépend, avez-vous besoin d'un code compatible croisé ou simplement d'un code compatible Python 3? Le test unitaire a-t-il échoué sur Py 2 ou Py 3?
Code compatible croisé. Le test unitaire a échoué sur python 2, mais la logique était un peu vague, qu'ils comparent les clés, les sous-ensembles ou la longueur des dictionnaires.
Votre linter a fait la bonne chose (en remplaçant les éléments d'affichage par des éléments) pour convertir le code py2 -> py3. Mais ce n'est pas un code de compatibilité croisée. Pour cela, vous devrez utiliser six.viewitems ou similaire, comme la réponse mentionnée.
J'ai répondu à une question similaire ici: Comportement incohérent entre l'égalité dict.values () et dict.keys () en Python 3.x et Python 2.7
La chose clé à noter est que dict.viewitems ( ) est un objet Set-like . Ce qui signifie que lorsque vous faites d1.viewitems () vous comparez en vérifiant si d1.viewitems () est un sous-ensemble em> de d2.viewitems () , pas la comparaison de longueur attendue. Consultez la documentation ici: https://docs.python.org/2.7 /library/sets.html#set-objects
>>> d1 = {'a': 0}
>>> d2 = {'a': 1}
>>> d3 = {'a': 0, 'b': 1}
>>> d1.viewitems() <= d3.viewitems()
True # because [('a', 0)] is a subset of [('a', 0), ('b', 1)]
>>> d2.viewitems() <= d3.viewitems()
False # because [('a', 1)] is not a subset of [('a', 0), ('b', 1)]
Remarque: comme dict.viewitem () est un objet collections.Set , il n'a pas .issubset ou .issuperset comme le fait set .
Observez ce qui suit:
Operation Equivalent Result s.issubset(t) s <= t test whether every element in s is in t s.issuperset(t) s >= t test whether every element in t is in s
Si vous souhaitez comparer des tailles de dictionnaires, faites-le explicitement:
len (d1). boo, python 2.x!
Python 2.7 n'a pas défini ce que signifierait exactement
d1 <= d2. Depuis docs.python.org/2.7/reference/expressions.html#comparisons a>: "Les mappages (instances de dict) comparent égaux si et seulement s'ils ont des paires égales (clé, valeur). La comparaison d'égalité des clés et des valeurs renforce la réflexivité. Les résultats autres que l'égalité sont résolus de manière cohérente, mais ne sont pas définis autrement. "À moins que vous ne mainteniez le code Python 2 hérité, vous ne devriez pas vous inquiéter de la sémantique;
d1 <= d2est une erreur de type dans Python 3, vous obligeant à utiliserlen (d1) <= len (d2).@chepner oui, à la recherche de la compatibilité python 3
Aussi, comment rendre cela compatible avec Python 3? - faire quelle partie spécifiquement? Vous avez démontré plusieurs choses ici.
Que voulez-vous que la règle soit, qui décide si le contenu d'un dict est "inférieur" aux autres?
Double possible de Comportement incohérent entre dict.values ( ) et l'égalité dict.keys () en Python 3.x et Python 2.7