Який найбільш пітонічний спосіб перевірити, якщо кілька змінних не є None?


79

Якщо у мене є така конструкція:

def foo():
    a=None
    b=None
    c=None

    #...loop over a config file or command line options...

    if a is not None and b is not None and c is not None:
        doSomething(a,b,c)
    else:
        print "A config parameter is missing..."

Який кращий синтаксис у python, щоб перевірити, чи всі змінні встановлені на корисні значення? Це так, як я писав, чи інший кращий спосіб?

Це відрізняється від цього питання: не None тест в Python ... Я шукаю найкращий метод для перевірки, якщо багато умов не є None. Варіант, який я набрав, здається дуже довгим і непітонічним.


2
Можливий дублікат тесту not None в Python
schwobaseggl

Я перевіряю наявність чотирьох змінних, і я також вважав, що очевидне рішення, яке ви опублікували, не дуже пітонічне. Мені прикро з-за відсутності відповідей зробити висновок, що, схоже, не існує "приємнішого" шляху.
веді

3
@schwobaseggl: Ні, це не дублікат, оскільки питання не в тому, як перевірити на None. Йдеться про те, як зробити так, щоб він "виглядав більш пітонічним" при перевірці декількох змінних, але не так багато, щоб виправити запропоноване рішення Даніелем Роузманом.
веді

Відповіді:


83

У тому, як ви це робите, немає нічого поганого.

Якщо у вас багато змінних, ви можете додати їх до списку та використовувати all:

if all(v is not None for v in [A, B, C, D, E]):

107

Насправді це можна зробити набагато простіше

if None not in (a, b, c, d):
    pass

ОНОВЛЕННЯ:

Як правильно зауважив slashCoder, наведений вище код неявно робить a == None, b == None тощо. На цю практику не звертають уваги. Оператор рівності може бути перевантажений, а не None може стати рівним None. Можна сказати, що цього ніколи не буває. Ну ні, поки не стане. Отже, щоб бути в безпеці, якщо ви хочете перевірити, що жоден з об’єктів не є None, ви можете використовувати цей підхід

if not [x for x in (a, b, c, d) if x is None]:
    pass

Це трохи повільніше і менш виразно, але все одно досить швидко і коротко.


4
Так! І це теж в 10 разів швидше! (Відповідно до timeit)
Прайнд,

3
Проблема в цьому полягає в тому, що оператори inand not inвиконують перевірку рівності щодо кожного елемента колекції, що не рекомендується у PEP8.
slashCoder

2
Зверніть увагу, що це умова Йоди ( en.wikipedia.org/wiki/Yoda_conditions ), і його слід використовувати з обережністю.
Chandrahas Aroori

1
@Chandrahas Aroori: Hrrmmm. Будьте обережні!
serge.v

7

Я знаю, що це старе питання, але я хотів додати відповідь, яка, на мою думку, є кращою.

Якщо всі елементи, які потрібно перевірити, є хешуючими, ви можете використовувати набір замість списку або кортежу.

>>> None not in {1, 84, 'String', (6, 'Tuple'), 3}

Це набагато швидше, ніж методи в інших відповідях.

>>> import timeit
>>> timeit.timeit("all(v is not None for v in [1, 84, 'String', (6, 'Tuple'), 3])")
1.7880705000000034
>>> timeit.timeit("None not in [1, 84, 'String', (6, 'Tuple'), 3]")
0.35424169999998867
>>> timeit.timeit("None not in (1, 84, 'String', (6, 'Tuple'), 3)")
0.3454340999999772
>>> timeit.timeit("None not in {1, 84, 'String', (6, 'Tuple'), 3}")
0.09577370000002361

Ще однією перевагою цього методу є те, що він дає вам правильну відповідь, навіть якщо хтось визначає __eq__метод класу, який потрібно завжди повертати True. (Звичайно, якщо вони визначають __hash__метод return hash(None), цей метод не буде працювати. Але ніхто не повинен цього робити, оскільки це перешкоджає меті визначення хешу.)

class my_int(int):
    def __init__(self, parent):
        super().__init__()

    def __eq__(self, other):
        return True

    def __hash__(self):
        return hash(super())

print(all(v is not None for v in [1, my_int(6), 2])) # True (correct)
print(None not in [1, my_int(6), 2])                 # False (wrong)
print(None not in (1, my_int(6), 2))                 # False (wrong)
print(None not in {1, my_int(6), 2})                 # True (correct)

чому дикт швидший за список та кортеж?
zheyuanWang

1
@zheyuanWang Щоб перевірити, чи є елемент у списку, елемент порівнюється з кожним елементом списку. Тобто O(n). У випадку набору, однак, Python просто обчислює хеш елемента та перевіряє, чи має набір дійсний запис для зазначеного хешу. Це таке O(1).
tfpf

4

Написання окремої відповіді, оскільки я не знаю, як відформатувати код, доданий як коментар.

Рішення Eternal_N00B не є таким, як рішення Даніеля Роузмена. Розглянемо для прикладу:

>>> усі (v не є None для v у [False])
Правда
>>> усі ([помилково])
помилковий

3

Для конкретного випадку, представленого ОП

if not all([a, b, c])

буде достатньо.

all([a, b, c])

обчислює значення False, якщо якийсь параметр відсутній.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.