2016-10-10 7 views
3

Я работаю на project, где встал вопрос о следующей строке:Лучшая практика Python: серия «или» или «в»?

a == "EQUAL" or a == "NOT EQUAL" or a == "LESS" or a == "GREATER" 

Я предложил изменения, чтобы сделать его «проще», как так:

a in ["EQUAL", "NOT EQUAL", "LESS", "GREATER"] 

Что будет считаться лучшим практика и что было бы лучше всего для производительности? Это для кода пользовательского интерфейса, который часто обновляется, поэтому незначительные улучшения производительности могут быть заметны. Я знаю, что первый пример будет «неудачным», если таковой обнаружен, и я предполагаю, что второй будет также.

Кроме того, не было бы даже быстрее использовать Dict как:

a in {"EQUAL", "NOT EQUAL", "LESS", "GREATER"} 

... так что список не должен был бы быть построен?

Единственное PEP-8 говорит (что я мог бы найти):

... код читается гораздо чаще, чем написано. Рекомендации, приведенные здесь, предназначены для улучшения читаемости кода ...

Однако, знайте, когда нужно быть непоследовательным - иногда рекомендации по руководству по стилю не применимы. Когда вы сомневаетесь, используйте свое лучшее суждение. Посмотрите на другие примеры и решите, что выглядит лучше всего.

+10

Ваш 'dict' является' set', но кроме того, что это хороший вариант. – Matthias

+0

@Matthias Что было бы проблемой с набором (кроме отсутствия порядка, который здесь не является проблемой)? – JakeD

+2

Нет проблем с набором. Просто используйте его. – Matthias

ответ

3

Я бы пошел с комплектом. Это гораздо более читаемо. Строка or s может быть быстрее в некоторых случаях, так как короткие замыкания оператора и нет накладных расходов на создание списка элементов каждый раз, но я не думаю, что это стоит жертвы читабельности. Вот быстрый и грязный бенчмарк. Это относится к Python 2.7

def t1(x): 
    return (x == "Foo" or x == "Bar" or x == "Baz" or x == "Quux")                      


def t2(x): 
    return x in {"Foo", "Bar", "Baz", "Quux"} 

[2.7.9]>>> import timeit 
[2.7.9]>>> timeit.timeit(lambda : t1("Quux"))                             
0.22514700889587402 
[2.7.9]>>> timeit.timeit(lambda : t1("Foo"))                             
0.18890380859375 
[2.7.9]>>> timeit.timeit(lambda : t2("Quux"))                             
0.27969884872436523 
[2.7.9]>>> timeit.timeit(lambda : t2("Foo"))                             
0.25904297828674316 

Python 3 номера.

[3.4.2]>>> timeit.timeit(lambda : t1("Quux")) 
0.25126787397312 
[3.4.2]>>> timeit.timeit(lambda : t1("Foo")) 
0.1722603400121443 
[3.4.2]>>> timeit.timeit(lambda : t2("Quux")) 
0.18982669000979513 
[3.4.2]>>> timeit.timeit(lambda : t2("Foo")) 
0.17984321201220155 
+1

Было бы интересно посмотреть, сколько времени потребуется, если элемент * не * действителен, например. ' "Foobar"'. – MisterMiyagi

+2

В более поздних версиях python установленная версия намного более конкурентоспособна. В python2 набор перестраивается каждый раз. В более поздних версиях, поскольку набор никогда не мутируется, компилятор создает фризонет в момент компиляции и кэширует его. – Dunes

1

Очевидно, что в вашем случае лучше использовать оператор in. Это гораздо более удобочитаемо.

В более сложных случаях, когда это не представляется возможным использовать in оператора, вы можете использовать all и any функции:

operations = {'EQUAL', 'NOT EQUAL', 'LESS', 'GREATER'} 
condition1 = any(curr_op.startswith(op) for op in operations) 

condition2 = all([ 
    self.Operation == "EQUAL", 
    isinstance(self.LeftHandSide, int), 
    isinstance(self.RightHandSide, int), 
]) 
+0

Это было бы хуже любого подхода, поскольку вы каждый раз оцениваете все. любой из них также медленный. –

+0

@PadraicCunningham не будет, если вы используете генераторы. – skovorodkin

+1

Да, но вы не были до тех пор, пока вы не отредактировали, а вторая все еще находится в списке, чтобы вы все равно оценивали каждый из них каждый раз. –

1

Как было предложено несколько человек, пойти на reability.

Производительность с учетом разницы, оператор in на множестве имеет среднее время поиска O (1), а для списков - O (n). Вы можете найти это here.

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

Простой пример может показать это: Для множеств:

operation = 9999999 
lookupSet = {i for i in range(0,10000000)} 
%timeit operation in lookupSet 
>> 10000000 loops, best of 3: 89.4 ns per loop 

где со списками:

operation = 9999999 
lookupList = [i for i in range(0,10000000)] 
%timeit operation in lookupList 
>> 10 loops, best of 3: 168 ms per loop 
Смежные вопросы