Python if not = = vs if!=
Jaka jest różnica między tymi dwoma liniami kodu:
if not x == 'val':
I
if x != 'val':
Czy jeden jest bardziej wydajny od drugiego?
Would it be better to use
if x == 'val':
pass
else:
7 answers
Za pomocą dis
aby spojrzeć na kod bajtowy wygenerowany dla dwóch wersji:
not ==
4 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 2 (==)
9 UNARY_NOT
10 RETURN_VALUE
!=
4 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 3 (!=)
9 RETURN_VALUE
Ta ostatnia ma mniej operacji, a zatem prawdopodobnie będzie nieco bardziej wydajna.
Zwrócono uwagę w Komendzie (Dzięki, @Quincunx ), że gdzie masz if foo != bar
vs. if not foo == bar
liczba operacji jest dokładnie taka sama, tylko że COMPARE_OP
zmienia się i POP_JUMP_IF_TRUE
przełączniki do POP_JUMP_IF_FALSE
:
not ==
:
2 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_TRUE 16
!=
2 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 3 (!=)
9 POP_JUMP_IF_FALSE 16
W tym przypadku, o ile nie było różnicy w ilości pracy wymaganej dla każdego porównania, jest mało prawdopodobne, że w ogóle zauważysz różnicę wydajności.
Należy jednak pamiętać, że obie wersje nie zawsze będą logicznie identyczne , ponieważ będą zależeć od implementacji __eq__
i __ne__
dla danych obiektów. Na model danych dokumentacja :
Między operatorami porównania nie istnieją żadne implikowane relacje. Na prawda
x==y
nie oznacza, żex!=y
jest fałszywa.
Na przykład:
>>> class Dummy(object):
def __eq__(self, other):
return True
def __ne__(self, other):
return True
>>> not Dummy() == Dummy()
False
>>> Dummy() != Dummy()
True
Wreszcie, i być może najważniejsze: ogólnie, gdzie dwa są logicznie identyczne, x != y
jest znacznie bardziej czytelny niż not x == y
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:28
@jonrsharpe ma doskonałe wyjaśnienie tego, co się dzieje. Pomyślałem, że po prostu pokażę różnicę w czasie, gdy uruchamiam każdą z 3 opcji 10,000,000 razy (wystarczająco, aby pokazać niewielką różnicę).
Użyty kod:
def a(x):
if x != 'val':
pass
def b(x):
if not x == 'val':
pass
def c(x):
if x == 'val':
pass
else:
pass
x = 1
for i in range(10000000):
a(x)
b(x)
c(x)
I wyniki profilera cProfile:
Widzimy więc, że pomiędzy if not x == 'val':
i if x != 'val':
istnieje bardzo mała różnica wynosząca ~0,7%. Z nich if x != 'val':
jest najszybszy.
Jednak, co najbardziej zaskakujące, widzimy, że
if x == 'val':
pass
else:
Jest w rzeczywistości najszybszy i bije if x != 'val':
o ~0,3%. To nie jest zbyt czytelne, ale myślę, że jeśli chcesz nieznaczną poprawę wydajności, można pójść tą drogą.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 13:33:55
W pierwszej z nich Python musi wykonać jeszcze jedną operację niż jest to konieczne(zamiast sprawdzać, czy nie jest równe, musi sprawdzić, czy nie jest prawdą, że jest równe, a więc jeszcze jedną operację). Nie da się odróżnić od jednego wykonania, ale jeśli uruchamiane wiele razy, drugie byłoby bardziej wydajne. Ogólnie użyłbym drugiego, ale matematycznie są takie same
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 12:43:46
>>> from dis import dis
>>> dis(compile('not 10 == 20', '', 'exec'))
1 0 LOAD_CONST 0 (10)
3 LOAD_CONST 1 (20)
6 COMPARE_OP 2 (==)
9 UNARY_NOT
10 POP_TOP
11 LOAD_CONST 2 (None)
14 RETURN_VALUE
>>> dis(compile('10 != 20', '', 'exec'))
1 0 LOAD_CONST 0 (10)
3 LOAD_CONST 1 (20)
6 COMPARE_OP 3 (!=)
9 POP_TOP
10 LOAD_CONST 2 (None)
13 RETURN_VALUE
Tutaj widać, że not x == y
mA o jedną instrukcję więcej niż x != y
. Tak więc różnica w wydajności będzie bardzo mała w większości przypadków, chyba że robisz miliony porównań, a nawet wtedy prawdopodobnie nie będzie to przyczyną wąskiego gardła.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 12:46:07
Dodatkowa uwaga, ponieważ inne odpowiedzi odpowiedziały na twoje pytanie w większości poprawnie, jest taka, że jeśli klasa definiuje tylko __eq__()
, a nie __ne__()
, to twoja COMPARE_OP (!=)
uruchomi __eq__()
i zaneguje to. W tym czasie trzecia opcja może być nieco bardziej wydajna, ale powinna być rozważana tylko wtedy, gdy potrzebujesz prędkości, ponieważ trudno ją szybko zrozumieć.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 13:27:07
Chodzi o twój sposób czytania. not
operator jest dynamiczny, dlatego możesz go zastosować w
if not x == 'val':
Ale !=
może być odczytany w lepszym kontekście jako operator, który robi odwrotnie niż ==
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 12:50:04
Chcę rozszerzyć mój komentarz czytelności powyżej.
Ponownie, całkowicie zgadzam się z czytelnością nad innymi (wydajność-nieistotne) obawy.
Chciałbym zwrócić uwagę na to, że mózg interpretuje "pozytywne" szybciej niż"negatywne". Np. " stop "vs." do not go " (dość kiepski przykład ze względu na różnicę w liczbie słów).
Więc wybór:
if a == b
(do this)
else
(do that)
Jest lepsze od funkcjonalnie równoważnego:
if a != b
(do that)
else
(do this)
Mniej czytelność / zrozumiałość prowadzi do większej liczby błędów. Być może nie w początkowym kodowaniu, ale (nie tak inteligentny jak ty!) zmiany konserwacyjne...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-01 13:24:37