while(1)とwhile(True)—なぜ違いがあるのですか(python 2バイトコードで)?


115

perlの無限ループに関するこの質問に興味をそそられます:while(1)Vs。for(;;)速度に違いはありますか?、私はpythonで同様の比較を実行することを決めました。コンパイラーがwhile(True): passとに対して同じバイトコードを生成することを期待していましたwhile(1): passが、これは実際にはpython2.7では当てはまりません。

次のスクリプト:

import dis

def while_one():
    while 1:
        pass

def while_true():
    while True:
        pass

print("while 1")
print("----------------------------")
dis.dis(while_one)

print("while True")
print("----------------------------")
dis.dis(while_true)

次の結果が生成されます。

while 1
----------------------------
  4           0 SETUP_LOOP               3 (to 6)

  5     >>    3 JUMP_ABSOLUTE            3
        >>    6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        
while True
----------------------------
  8           0 SETUP_LOOP              12 (to 15)
        >>    3 LOAD_GLOBAL              0 (True)
              6 JUMP_IF_FALSE            4 (to 13)
              9 POP_TOP             

  9          10 JUMP_ABSOLUTE            3
        >>   13 POP_TOP             
             14 POP_BLOCK           
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE        

使用while Trueは著しく複雑です。どうしてこれなの?

他のコンテキストでは、python Trueは1と同じように動作します。

>>> True == 1
True

>>> True + True
2

なぜwhile2つを区別するのですか?

私はpython3が同じ操作を使用してステートメントを評価していることに気づきました:

while 1
----------------------------
  4           0 SETUP_LOOP               3 (to 6) 

  5     >>    3 JUMP_ABSOLUTE            3 
        >>    6 LOAD_CONST               0 (None) 
              9 RETURN_VALUE         
while True
----------------------------
  8           0 SETUP_LOOP               3 (to 6) 

  9     >>    3 JUMP_ABSOLUTE            3 
        >>    6 LOAD_CONST               0 (None) 
              9 RETURN_VALUE         

python3でブール値の評価方法に変更はありますか?


回答:


124

Python 2.xでは、Trueはキーワードではなく、型で1に定義されている組み込みのグローバル定数にすぎませんbool。したがって、インタプリタは引き続きのコンテンツをロードする必要がありTrueます。つまり、Trueは再割り当て可能です。

Python 2.7 (r27:82508, Jul  3 2010, 21:12:11) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4
>>> True
4

Python 3.xでは、それは本当にキーワードと実際の定数になります。

Python 3.1.2 (r312:79147, Jul 19 2010, 21:03:37) 
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4
  File "<stdin>", line 1
SyntaxError: assignment to keyword

したがって、インタプリタはwhile True:ループを無限ループに置き換えることができます。


1
@MH:AFAIK、キーワードを言語に取り入れることは好都合でした。
S.Lott 09/10/28

2
歴史の一部については、docs.python.org / whatsnew / 2.3.html #pep-285-a-boolean-typeおよびpython.org/dev/peps/pep-0285を参照してください。
Ned Deily

これはどういう意味while 1while TrueはPython 3で同じですか?
Stevoisiak

@ StevenM.Vascellaroはい。
kennytm

14

これは正しくありません、

したがって、インタプリタは、while True:ループを無限ループに置き換えることができます。

ループから抜け出すことができるからです。しかし、そのようなループのelse句がPython 3ではアクセスされないことは事実です。また、値のルックアップを単純化するとwhile 1、Python 2と同じようにすばやく実行できることも事実です。

性能比較

やや重要なwhileループの時間の違いを示します。

セットアップ

def while1():
    x = 0
    while 1:
        x += 1
        if x == 10:
            break

def whileTrue():
    x = 0
    while True:
        x += 1
        if x == 10:
            break

Python 2

>>> import timeit
>>> min(timeit.repeat(while1))
0.49712109565734863
>>> min(timeit.repeat(whileTrue))
0.756627082824707

Python 3

>>> import timeit
>>> min(timeit.repeat(while1))
0.6462970309949014
>>> min(timeit.repeat(whileTrue))
0.6450748789939098

説明

違いを説明するために、Python 2では:

>>> import keyword
>>> 'True' in keyword.kwlist
False

しかしPython 3では:

>>> import keyword
>>> 'True' in keyword.kwlist
True
>>> True = 'true?'
  File "<stdin>", line 1
SyntaxError: can't assign to keyword

TrueはPython 3のキーワードなので、インタプリタは値を調べて、誰かが他の値に置き換えたかどうかを確認する必要はありません。ただし、True別の値に割り当てることができるため、インタプリタは毎回それを調べる必要があります。

Python 2のまとめ

Python 2でタイトで長時間実行されるループがある場合は、のwhile 1:代わりに使用する必要がありますwhile True:

Python 3のまとめ

while True:ループから抜け出すための条件がない場合に使用します。


3

これは7年前の質問で、すでにすばらしい回答がありますが、質問の誤解は、回答のいずれにも記載されていないため、重複としてマークされている他の質問のいくつかを混乱させる可能性があります。

他のコンテキストでは、PythonはTrueが1に等しいかのように動作します。

>>> True == 1
True

>>> True + True
2

なぜ2つを区別しているのですか?

実際、whileここでは何も変わっていません。これは、例1Trueはまったく同じ方法で区別+します。


ここに2.7があります:

>>> dis.dis('True == 1')
  1           0 LOAD_GLOBAL              0 (True)
              3 LOAD_CONST               1 (1)
              6 COMPARE_OP               2 (==)
              9 RETURN_VALUE

>>> dis.dis('True == 1')
  1           0 LOAD_GLOBAL              0 (True)
              3 LOAD_GLOBAL              0 (True)
              6 BINARY_ADD
              9 RETURN_VALUE

次に比較します。

>>> dis.dis('1 + 1')
  1           0 LOAD_CONST               1 (2)
              3 RETURN_VALUE

これは、発光だLOAD_GLOBAL (True)それぞれにTrue、オプティマイザは、グローバルにできることは何もありません。だから、while区別1Trueまったく同じ理由で+行います。(そして==、オプティマイザは比較を最適化しないため、それらを区別しません。)


ここで3.6を比較します。

>>> dis.dis('True == 1')
  1           0 LOAD_CONST               0 (True)
              2 LOAD_CONST               1 (1)
              4 COMPARE_OP               2 (==)
              6 RETURN_VALUE

>>> dis.dis('True + True')
  1           0 LOAD_CONST               1 (2)
              2 RETURN_VALUE

ここLOAD_CONST (True)では、オプティマイザが利用できるキーワードのa を発行しています。だから、True + 1 しない、まったく同じ理由がために、区別while Trueしません。(そして==、オプティマイザは比較を最適化しないため、それらを区別しません。)


一方、コードが最適化されていない場合、インタプリタはこれらの3つのケースすべてで扱いTrue1まったく同じになります。boolサブクラスでありint、そして継承最もそのメソッドのからint、とTrueあなたがやっているかどうか、1だから、内部の整数値を持っているwhile(テスト__bool__3.xでは、__nonzero__2.xで)を、比較(__eq__)、または算術(__add__)、Trueまたはのどちらを使用しても同じメソッドを呼び出します1

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.