Pylint에서 잘못된 것으로 간주되는 조건 값에 len (SEQUENCE)을 사용하는 이유는 무엇입니까?


211

이 코드 스 니펫을 고려하면 :

from os import walk

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

나는 if 문이있는 줄에 관한이 메시지와 함께 Pylint에 놀랐습니다.

[pylint] C1801 : len(SEQUENCE)조건 값으로 사용하지 마십시오

규칙 C1801은 언뜻보기에 매우 합리적으로 들리지 않았으며 참조 안내서정의 는 이것이 왜 문제인지 설명하지 않습니다. 사실, 그것은 그것을 옳지 않은 사용 이라고 부릅니다 .

len-as-condition (C1801) : Pylint가 조건 내부에서 len (sequence)의 잘못된 사용을 감지 할 때 사용 len(SEQUENCE)되는 조건 값으로 사용 하지 마십시오 .

나의 검색 시도도 나에게 더 깊은 설명을 제공하지 못했습니다. 나는 시퀀스의 길이 속성이 느리게 평가 __len__될 수 있고 부작용을 갖도록 프로그래밍 될 수 있음을 이해하지만 Pylint가 그러한 사용을 잘못 사용하기에 충분히 문제가되는지 여부는 의문의 여지가 있습니다. 따라서 규칙을 무시하도록 프로젝트를 간단하게 구성하기 전에 추론에 뭔가 빠졌는지 여부를 알고 싶습니다.

len(SEQ)조건 값으로 사용하는 것이 언제 문제가됩니까? Pylint가 C1801로 피하려고하는 주요 상황은 무엇입니까?


9
시퀀스의 진실성을 직접 평가할 수 있기 때문입니다. pylint는 당신이하기를 원 if files:하거나if not files:
Patrick Haugh

38
len그것이 호출되는 컨텍스트를 알지 못하므로 길이를 계산하는 것이 전체 시퀀스를 순회하는 것을 의미하는 경우 길이를 계산해야합니다. 결과가 단지 0과 비교되고 있다는 것을 알지 못합니다. 부울 값 계산은 시퀀스의 실제 길이에 관계없이 첫 번째 요소를 본 후에 중지 될 수 있습니다. 나는 pylint가 여기에 약간의 의견이 있다고 생각합니다. 나는 그것을 사용 하는 것이 잘못 된 상황을 생각할 수 없다 len. 단지 대안보다 더 나쁜 옵션이라는 것이다.
chepner

2
@ E_net4 PEP-8 이 시작의 장소 라고 생각합니다 .
Patrick Haugh


6
시퀀스에는 C ++ imo와 같은 'empty ()'또는 'isempty ()'가 필요합니다.
JDonner

답변:


281

len(SEQ)조건 값으로 사용하는 것이 언제 문제가됩니까? Pylint가 C1801로 피하려고하는 주요 상황은 무엇입니까?

그것은 아니에요 정말 사용에 문제가 len(SEQUENCE)- 그것은 (참조 효율적으로되지 않을 수 있지만 chepner의 의견을 ). Pylint는 PEP 8 스타일 가이드 를 준수하는지 코드를 확인 합니다.

시퀀스 (문자열, 목록, 튜플)의 경우 빈 시퀀스가 ​​거짓이라는 사실을 사용하십시오.

Yes: if not seq:
     if seq:

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

언어 사이에서 우연히 나오는 가끔 파이썬 프로그래머로서, 나는 len(SEQUENCE)구문을 더 읽기 쉽고 명확하게 생각합니다 ( "명시 적 일수록 암시적일 것"). 그러나 False부울 컨텍스트에서 빈 시퀀스가 ​​평가된다는 사실을 사용하는 것이 "Pythonic"으로 간주됩니다.


이 작업을 수행하는 방법 :if len(fnmatch.filter(os.listdir(os.getcwd()), 'f_*')):
Marichyasana

@Marichyasana 나는 (이론적으로) if next(iter(...), None) is not None:시퀀스가 포함 할 수없는 경우 와 같이 쓸 수 있다고 생각 합니다 None. 그것은 len(fnmatch...)길지만 너무 길다. 둘 다 나눠야합니다.
Kirill Bulygin

13
나는 또한 가끔 파이썬 사용자이고 종종 "Pythonic way"가 그 자체의 모호함에 얽힌다는 느낌을받습니다.
luqo33

3
일반적인 질문입니다. 이러한 PEP 권장 사항을 수정할 수 있습니까? len(s) == 0내 의견이 우월한 또 다른 이유 는 다른 유형의 시퀀스에 대해 일반화 가능하기 때문입니다. 예를 들어 pandas.Seriesnumpy 배열입니다. if not s:반면에이 경우 가능한 모든 배열 유형 객체 (예 :)에 대해 별도의 평가를 사용해야합니다 pd.DataFrame.empty.
Marses

2
그건 그렇고, 어떤 of collections.abc클래스도 __bool__메소드를 명시 하지 않습니다 . 다른 말로, bool(seq)그것이 그것이 아는 경우 어떻게 사용할 수 있는지 어떻게 확신 할 수 collections.abc.Collection있습니까? 또한 일부 도서관 bool(collection)은 수업 을 확인하는 것이 금지되어 있다고 주장합니다 .
Eir Nym

42

NumPy 배열을 사용할 때 실제로 se (의 bool 값을 확인하는 대신) len (seq)을 사용해야합니다.

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

예외 : ValueError : 둘 이상의 요소가있는 배열의 실제 값이 모호합니다. a.any () 또는 a.all ()을 사용하십시오.

따라서 Python 목록과 NumPy 배열을 모두 사용하는 코드의 경우 C1801 메시지가 도움이되지 않습니다.


5
나는 당신의 진술에 동의합니다. 함께 문제점 # 1405 지금 제기, 내가 C1801을 볼 수 있도록 노력하겠습니다하거나 유용한 무언가를 개혁하거나 기본적으로 사용되지 않습니다.
E_net4는

2
또한 시퀀스에 주어진 수의 요소가 있는지 확인하는 데 쓸모가 없습니다. 최상의 경우에는 완전히 비어 있는지 확인하는 데만 좋습니다.
PabTorre

1

이것은 pylint의 문제였으며 더 이상 len(x) == 0잘못된 것으로 간주 하지 않습니다.

베어 len(x) 를 조건 으로 사용해서는 안됩니다 . 비교 len(x)와 같은 명시적인 값과 if len(x) == 0의 것은 if len(x) > 0완전히 잘하지 PEP (8)에 의해 금지되어 있습니다.

에서 PEP 8 :

# Correct:
if not seq:
if seq:

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

길이명시 적으로 테스트하는 것은 금지되지 않습니다. 파이썬선은 다음과 같이 말합니다.

암시적인 것보다 명시적인 것이 좋습니다.

if not seq및 사이의 선택 if not len(seq)에서 둘 다 암시 적이지만 동작이 다릅니다. 그러나 if len(seq) == 0또는 if len(seq) > 0명백한 비교이며 많은 상황에서 올바른 행동입니다.

pylint에서 PR 2815 는이 버그를 수정했으며 처음에는 이슈 2684 로보고되었습니다 . 그것에 대해 계속 불평 if len(seq)하지만 더 이상 불평하지 않습니다 if len(seq) > 0. PRyl은 2019-03-19에 병합되었으므로 pylint 2.4 (2019-09-14 릴리스)를 사용하는 경우이 문제가 표시되지 않습니다.


0

Pylint는 내 코드에 실패했으며 연구를 통해이 게시물로 연결되었습니다.

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

이것은 전에 내 코드였습니다.

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

이것은 내 코드 수정 후였습니다. 를 사용함으로써 int() attributePep8 / Pylint를 만족시킨 것 같고 내 코드에 부정적인 영향을 미치지 않는 것 같습니다.

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

내 수정

.__trunc__()시퀀스에 추가함으로써 필요를 해결 한 것으로 보입니다.

나는 행동에 차이가 보이지 않지만 내가 누락 된 세부 사항을 아는 사람이 있으면 알려주십시오.


1
__trunc__()의 출력을 호출 len(seq)하면 길이 값을 정수로 자릅니다. 보푸라기 뒤에있는 이유를 다루지 않고 보푸라기 만 "실신합니다". 허용 된 답변의 제안이 효과가 없습니까?
E_net4는 귀엽지 않다

내 시도에는 없습니다. 중복성을 이해하지만 github.com/PyCQA/pylint/issues/1405 & 2684 의 개발자가이 문제를 해결하고 병합 한 후에도 pylint를 실행할 때 문제가되지 않아야한다는 것을 이해합니다 pylint를 업데이트 한 후에도 여전히이 문제가 나타납니다. this worked for me전적으로 적절하지 않더라도 공유하고 싶었습니다 . 그러나 len (seq) == 0 비교를 수행하는 경우 중복되는 경우에도 명확히하기 위해 trunc 는 이미 정수이므로 아무것도 할 필요가 없습니다. 권리?
JayRizzo

1
정확히, 그것은 이미 정수이며, __trunc__()의미있는 일을 하지 않습니다. 필자는 비교가 중복되는 것이 아니라 길이를 자르려는 시도를 언급했습니다. 경고는 양식의 표현 만 기대하기 때문에 사라집니다 len(seq) == 0. 이 경우 보푸라기가 if 문을 다음과 같이 대체 할 것으로 예상합니다.if not dirnames and not filenames:
E_net4는 귀엽지 않습니다.

__bool__기능이 기본 순서로 정의되지 않은 경우 진실성을 테스트하면 의도하지 않은 결과가 "항상 참"이됩니다 .
Erik Aronesty
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.