Использование IF, AND, OR вместе с операндом EQUAL вместе в Python

Я пытаюсь создать функцию, в которой заданное значение (переданное в виде строки) проверяется, чтобы увидеть, равно ли количество цифр 4 или 6, и что это число.

Моим первым импульсом было использовать этот код:

def number(x):
    if (len(x) == (4 or 6)) and x.isdigit():
        print "True"
    else:
        print "False"

Этот код выше проходит только первый тест ниже... Я не понимаю, почему он проходит это, но ни один из других тестов:

number("1234")

Только когда я отделю функции len(), все будет работать правильно.

def number(x):
    if (len(x) == 4 or len(x) == 6) and x.isdigit():
        print "True"
    else:
        print "False"


## Checks
number("1234")
number("123456")
number("abcd")
number("abcdef")
number("1")
number("a")

Приведенный выше код проходит все тесты.

Итак, мои вопросы:

  1. Что тут происходит?
  2. Любой способ написать более чистый код для этого?

Спасибо за помощь!

** Не повторяющийся вопрос, потому что, хотя этот вопрос имеет те же основные концепции, касающиеся логических операторов, сама проблема отличается из-за использования len(), isdigit() и дополнительного вопроса о том, как лучше всего его улучшить (кто-то прокомментировал использование возврата). Тем не менее, определенно добавляет другую точку зрения на другой вопрос.


person jhub1    schedule 20.07.2016    source источник
comment
Подсказка: что оценивает (4 or 6) сам по себе? len(x) равно этому?   -  person OneCricketeer    schedule 20.07.2016
comment
Не дубликат. Даже не близко. Да, оба вопроса решаются чтением того же комплекта мануала, а не дубликата.   -  person Charles Merriam    schedule 20.07.2016


Ответы (6)


Это помогает изучить логику этой строки:

if (len(x) == (4 or 6)):

Предложение (4 or 6) содержит логическое короткое замыкание or. Значение 4 истинно, поэтому оно вычисляется и возвращается к реляционному сравнению ==.

Принцип работы or заключается в том, что его левая часть оценивается на предмет логической истинности, и ее значение возвращается, если оно истинно. Если левая часть не является логической истиной, то оценивается правая часть и возвращается ее значение.

Поскольку левая часть 4 or ... верна в логическом смысле, правая часть никогда не вычисляется. Python даже не смотрит дальше 4 or. Если бы левое значение было ложным (например, 0), тогда оценивалась бы правая часть or.

Чтобы увидеть это в действии, попробуйте print 4 or 6. Выход будет 4.

Итак, поскольку 4 является жестко запрограммированным истинным значением, ваше сравнение семантически такое же, как if (len(x) == 4), то есть, поскольку 4 истинно, 6 никогда не оценивается.

Я полагаю, что вы действительно хотите знать, является ли len(x) 4 или 6. Вы можете поместить это в код несколькими способами:

if(len(x) == 4 or len(x) == 6 ...

if(len(x) in (4,6) ...
person DavidO    schedule 20.07.2016
comment
Как ни странно, в моем случае это ведет себя иначе: Здесь учитываются оба › if file.endswith(".log") or file.endswith(".blg"): Здесь учитывается только левая сторона › if file.endswith(".log" or ".blg"): - person Matthieu Ducorps; 07.02.2019

Вы можете использовать оператор in следующим образом:

def number(x):
    if len(x) in (4, 6) and x.isdigit():
    print "True"
else:
    print "False"

где in проверяет содержание в данном контейнере. Обратите внимание, что 4 or 6 сами по себе оцениваются как нечто нежелательное, поэтому ваш первый сегмент кода терпит неудачу. Вы можете проверить это в оболочке Python:

>>> 4 or 6
4
person ifma    schedule 20.07.2016

Краткий ответ: len(x) in [4, 6] или len(x) == 4 or len(x) == 6.

"или" является логическим или логическим выбором. (4 или 6) гарантированно разрешается в ненулевое (истинное) значение. В этом случае он разрешается до 4, поэтому ваш тестовый пример проходит.

person Charles Merriam    schedule 20.07.2016
comment
У меня щелкнуло в голове после прочтения вашего ответа - спасибо. Для всех, кто читает это: критическая ошибка, которую я сделал, заключалась в том, что я не думал об ИЛИ как о логическом. - person jhub1; 20.07.2016

Вы наверное хотели написать

if (len(x) in (4, 6)) and x.isdigit():

Вместо

if (len(x) == (4 or 6)) and x.isdigit(): 
person jonas_toth    schedule 20.07.2016

Я пойду и отвечу

Любой способ написать более чистый код для этого?

да. Вернуть логическое значение, а не печатать строку.

def number(x): 
    return len(x) in {4, 6} and x.isdigit()

print(number("1234")) # True

Затем просто используйте ваш метод в операторе if без сравнения строк.

person OneCricketeer    schedule 20.07.2016
comment
Спасибо. Чтобы расширить это - если бы вы хотели синхронизировать обе эти функции, как бы вы это сделали? Я пробовал [Python -m timeit import упрощенный; упрощенный.номер() ] в консоли... но это не работает. упрощенный.py — это имя файла, в котором находится эта функция. - person jhub1; 20.07.2016
comment
Не уверен. Никогда не использовал timeit. Я хочу сказать, что это быстрее, потому что нет условного if-else - person OneCricketeer; 20.07.2016

Проблема в вашем утверждении or.

Любое значение больше единицы будет оценено как True, когда вы поместите его в условное выражение. Таким образом, (4 or 6) будет всегда принимать значение true.

Вы можете использовать оператор in выше, или вы можете просто использовать два ==:

if (len(x) == 4 or len(x) == 6) and x.isdigit()

Немного многословнее, мне легче читать.

person Athena    schedule 20.07.2016