web-dev-qa-db-fra.com

Pourquoi l'utilisation de len (SEQUENCE) dans les valeurs de condition est-elle considérée comme incorrecte par Pylint?

Considérant cet extrait de code:

from os import walk

files = []
for (dirpath, _, filenames) in walk(mydir):
    # more code that modifies files
if len(files) == 0: # <-- C1801
    return None

Pylint m'a alarmé avec ce message concernant la ligne avec la déclaration if:

[pylint] C1801: n'utilisez pas len(SEQUENCE) comme valeur de condition

La règle C1801, à première vue, ne me paraissait pas très raisonnable, et le définition sur le guide de référence n'explique pas pourquoi il s'agit d'un problème. En fait, il l'appelle carrément un usage incorrect .

len-as-condition (C1801) : Ne pas utiliser len(SEQUENCE) comme valeur de condition Utilisé lorsque Pylint détecte une erreur utilisation de len (séquence) à l'intérieur des conditions.

Mes tentatives de recherche ont également échoué à me fournir une explication plus profonde. Je comprends que la propriété de longueur d’une séquence puisse être évaluée paresseusement et que __len__ puisse être programmé pour avoir des effets secondaires, mais on peut se demander si cela est suffisamment problématique pour que Pylint appelle une telle utilisation incorrecte. Par conséquent, avant de configurer simplement mon projet pour ignorer la règle, j'aimerais savoir si quelque chose me manque dans mon raisonnement.

Quand l'utilisation de len(SEQ) en tant que valeur de condition pose-t-elle problème? Quelles sont les principales situations que Pylint tente d'éviter avec le C1801?

182
E_net4

Quand l'utilisation de len(SEQ) en tant que valeur de condition pose-t-elle problème? Quelles sont les principales situations que Pylint tente d'éviter avec C1801?

Il n’est pas vraiment problématique d’utiliser len(SEQUENCE) - bien que cela puisse ne pas être aussi efficace (voir commentaire de chepner ). Quoi qu’il en soit, Pylint vérifie la conformité du code avec le guide de style PEP 8 qui stipule que

Pour les séquences (chaînes, listes, tuples), utilisez le fait que les séquences vides sont fausses.

Yes: if not seq:
     if seq:

No:  if len(seq):
     if not len(seq):

En tant que programmeur Python occasionnel, qui navigue entre les langages, je considérerais que la construction len(SEQUENCE) est plus lisible et explicite ("Explicit vaut mieux qu'implicite"). Cependant, l'utilisation du fait qu'une séquence vide est évaluée à False dans un contexte booléen est considérée comme plus "Pythonique".

244
Anthony Geoghegan

Notez que l'utilisation de len (seq) est en fait requise (au lieu de simplement vérifier la valeur booléenne de seq) lors de l'utilisation de tableaux NumPy.

a = numpy.array(range(10))
if a:
    print "a is not empty"

génère une exception: ValueError: la valeur de vérité d'un tableau comportant plusieurs éléments est ambiguë. Utilisez a.any () ou a.all ()

Et par conséquent, pour le code qui utilise à la fois les listes Python et les tableaux NumPy, le message C1801 n’est pas utile.

35
Cameron Hayne

La prochaine version de Pylint ne devrait plus se plaindre après la correction (https://github.com/PyCQA/pylint/issues/2684 et https://github.com/PyCQA/pylint/ issues/1405

Merci à PaulRenvoise , PCManticore et adhearn pour le travail qu’ils ont accompli pour résoudre ce problème!

Par exemple, if len(files) == 0 ne fera plus se plaindre pylint.

4
Mateusz Konieczny

Pylint échouait pour mon code et les recherches m'ont conduit à ce poste:

../filename.py:49:11: C1801: Do not use `len(SEQUENCE)` to determine if a sequence is empty (len-as-condition)
../filename.py:49:34: C1801: Do not use `len(SEQUENCE)` to determine if a sequence is empty (len-as-condition)

C'était mon code avant:

def list_empty_folders(directory):
"""The Module Has Been Build to list empty Mac Folders."""
for (fullpath, dirnames, filenames) in os.walk(directory):
    if len(dirnames) == 0 and len(filenames) == 0:
        print("Exists: {} : Absolute Path: {}".format(
            os.path.exists(fullpath), os.path.abspath(fullpath)))

C'était après la correction de mon code. En utilisant la int()attribute, il semble que je sois satisfait de Pep8/Pylint et que cela ne semble pas avoir d'impact négatif sur mon code:

def list_empty_folders(directory):
"""The Module Has Been Build to list empty Mac Folders."""
for (fullpath, dirnames, filenames) in os.walk(directory):
    if len(dirnames).__trunc__() == 0 and len(filenames).__trunc__() == 0:
        print("Exists: {} : Absolute Path: {}".format(
            os.path.exists(fullpath), os.path.abspath(fullpath)))

Ma solution

En ajoutant .__trunc__() à la séquence, le besoin semble avoir été réglé.

Je ne vois pas de différence dans le comportement, mais si quelqu'un sait les détails qui me manquent, faites-le moi savoir.

0
JayRizzo