¿Por qué Pylint considera incorrecto el uso de len (SECUENCIA) en los valores de condición?

7 minutos de lectura

avatar de usuario
E_net4 – Sr. votante negativo

Teniendo en cuenta este fragmento de código:

from os import walk

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

Pylint me alarmó con este mensaje con respecto a la línea con la declaración if:

[pylint] C1801: No usar len(SEQUENCE) como valor de condición

La regla C1801, a primera vista, no me sonaba muy razonable, y la definición en la guía de referencia no explica por qué esto es un problema. De hecho, francamente lo llama un uso incorrecto.

lente como condición (C1801):
No utilice len(SEQUENCE) como valor de condición Se usa cuando Pylint detecta un uso incorrecto de len (secuencia) dentro de las condiciones.

Mis intentos de búsqueda tampoco han logrado proporcionarme una explicación más profunda. Entiendo que la propiedad de longitud de una secuencia puede evaluarse con pereza, y que __len__ puede programarse para tener efectos secundarios, pero es cuestionable si eso solo es lo suficientemente problemático como para que Pylint califique tal uso como incorrecto. Por lo tanto, antes de simplemente configurar mi proyecto para ignorar la regla, me gustaría saber si me estoy perdiendo algo en mi razonamiento.

¿Cuándo es el uso de len(SEQ) como un problema de valor de condición? ¿Qué situaciones importantes intenta evitar Pylint con C1801?

  • Porque puedes evaluar la veracidad de la secuencia directamente. pylint quiere que hagas if files: o if not files:

    –Patrick Haugh

    30 de marzo de 2017 a las 15:01

  • len no conoce el contexto en el que se llama, por lo que si calcular la longitud significa recorrer toda la secuencia, debe hacerlo; no sabe que el resultado solo se compara con 0. El cálculo del valor booleano puede detenerse después de ver el primer elemento, independientemente de la duración real de la secuencia. Sin embargo, creo que Pylint está siendo un poco obstinado aquí; No puedo pensar en ninguna situación en la que sea equivocado usar lensolo que es una peor opción que la alternativa.

    – Chepner

    30 de marzo de 2017 a las 15:04


  • @E_net4 creo que PEP-8 es probablemente el lugar para empezar.

    –Patrick Haugh

    30 de marzo de 2017 a las 15:14

  • Las SECUENCIAS necesitan un ‘vacío()’ o ‘isempty()’ como C++ imo.

    – JDonner

    23 de julio de 2018 a las 14:16

¿Cuándo es el uso de len(SEQ) como un problema de valor de condición? ¿Qué situaciones importantes intenta evitar Pylint con C1801?

No es De Verdad problemático de usar len(SEQUENCE) – aunque puede que no sea tan eficiente (ver el comentario de Chepner). Independientemente, Pylint verifica el código para el cumplimiento de la guía de estilo pep 8 el cual establece que

Para secuencias (cadenas, listas, tuplas), use el hecho de que las secuencias vacías son falsas.

Yes: if not seq:
     if seq:

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

Como programador ocasional de Python, que revolotea entre lenguajes, consideraría la len(SEQUENCE) construir para que sea más legible y explícito (“Explícito es mejor que implícito”). Sin embargo, usando el hecho de que una secuencia vacía se evalúa como False en un contexto booleano se considera más “Pythonic”.

  • Cómo hacer que esto funcione entonces: if len(fnmatch.filter(os.listdir(os.getcwd()), 'f_*')):

    – Marichyasana

    3 de agosto de 2017 a las 22:39

  • @Marichyasana Supongo que cosas como esa pueden (teóricamente) escribirse como if next(iter(...), None) is not None: (si la secuencia no puede contener None). Eso es largo, pero el len(fnmatch...) es largo también; ambos necesitan ser divididos.

    – Kirill Bulyguin

    8 de agosto de 2017 a las 12:06


  • También soy un usuario ocasional de Python y, a menudo, tengo la impresión de que el “modo Pythonic” se enredó en su propia ambigüedad.

    – luqo33

    13 de octubre de 2017 a las 9:18

  • Una pregunta general, ¿se pueden revisar estas recomendaciones del PEP? Otra razón por la cual el len(s) == 0 es superior en mi opinión es que es generalizable para otros tipos de secuencias. Por ejemplo, pandas.Series y matrices numpy. if not s: no es por otro lado, y en ese caso necesitaría usar una evaluación separada para todos los tipos posibles de objetos similares a matrices (es decir, pd.DataFrame.empty).

    – Marte

    26 de marzo de 2018 a las 16:49

  • Por cierto, ninguno of collections.abc estados de clases __bool__ método. En otras palabras, ¿cómo puedo estar seguro de que puedo usar bool(seq) si yo se que es un collections.abc.Collection? Además, algunas bibliotecas declaran que está prohibido verificar bool(collection) para sus clases.

    – Eir Nym

    11/10/2018 a las 15:33


Tenga en cuenta que, de hecho, se requiere el uso de len (seq) (en lugar de simplemente verificar el valor bool de seq) cuando se usan matrices NumPy.

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

da como resultado una excepción: ValueError: el valor de verdad de una matriz con más de un elemento es ambiguo. Use a.any() o a.all()

Y, por lo tanto, para el código que usa listas de Python y matrices NumPy, el mensaje C1801 es menos que útil.

  • Estoy de acuerdo con tu declaración. Con número 1405 ahora planteado, espero ver C1801 reformado a algo útil o deshabilitado por defecto.

    – E_net4 – Sr. votante negativo

    8 mayo 2017 a las 22:44

  • además, es inútil para comprobar si una secuencia tiene un número determinado de elementos. Solo sirve para comprobar que está completamente vacío en el mejor de los casos.

    – PabTorre

    14 de febrero de 2018 a las 15:38

avatar de usuario
Gerrit

Este fue un problema en Pylint, y ya no considera len(x) == 0 como incorrecto

No debe usar un desnudo len(x) como condición Comparando len(x) contra un valor explícito, como if len(x) == 0 de if len(x) > 0 está totalmente bien y no está prohibido por PEP 8.

De PEP 8:

# Correct:
if not seq:
if seq:

# Wrong:
if len(seq):
if not len(seq):

Tenga en cuenta que probando explícitamente la longitud no está prohibido. los zen de pitón estados:

Explícito es mejor que implícito.

En la elección entre if not seq y if not len(seq), ambos están implícitos, pero el comportamiento es diferente. Pero if len(seq) == 0 o if len(seq) > 0 son comparaciones explícitas y son en muchos contextos el comportamiento correcto.

En Pylint, PR 2815 ha solucionado este error, informado por primera vez como número 2684. Seguirá quejándose if len(seq)pero ya no se quejará if len(seq) > 0. El PR se fusionó el 19 de marzo de 2019, por lo que si está utilizando Pylint 2.4 (lanzado el 14 de septiembre de 2019), no debería ver este problema.

Pylint estaba fallando en mi código y la investigación me llevó a esta publicación:

../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)

Este era mi código antes:

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)))

Esto fue después de mi corrección de código. Al usar el int() attributeparece que he satisfecho Pep8/Pylint y no parece tener un impacto negativo en mi código:

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)))

mi solución

Añadiendo .__trunc__() a la secuencia parece haber asentado la necesidad.

No veo una diferencia en el comportamiento, pero si alguien sabe detalles que me faltan, hágamelo saber.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad