[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
疑問点
私の理解では
range()
関数は、実際には
Python 3 のオブジェクト型
で、ジェネレータのようにその場で内容を生成します。
というのも、1,000兆が範囲内かどうかを判断するためには、1,000兆個の値を生成しなければならないからだ。
1_000_000_000_000_000 in range(1_000_000_000_000_001)
さらに:0をいくつ付けても、多かれ少なかれ計算には同じ時間がかかるようです(基本的に瞬時)。
なども試しましたが、やはり計算はほぼ一瞬です。
# count by tens
1_000_000_000_000_000_000_000 in range(0,1_000_000_000_000_000_000_001,10)
自分でレンジ関数を実装しようとすると、結果はあまりいいものではありませんね
def my_crappy_range(N):
i = 0
while i < N:
yield i
i += 1
return
とは何ですか?
range()
オブジェクトはどのように高速化されているのでしょうか?
Martijn Pietersの回答
を選んだのは、その完成度の高さによるものですが、他にも
abarnertの最初の回答
にとってどういう意味があるのか、よく議論されています。
range
にすることで、本格的な
シーケンス
の潜在的な不整合に関するいくつかの情報と警告が表示されます。
__contains__
関数の最適化は、Python の実装の違いで異なります。
abarnertさんの他の回答
は、Python 3 での最適化の背後にある歴史に興味がある人のために、もう少し詳細な説明とリンクを提供しています。
xrange
Python 2 の場合)。回答
pokeで
と
ウィムによる
は、関連するC言語のソースコードと解説を提供していますので、興味のある方はご覧ください。
解決方法は?
Python 3
range()
オブジェクトはすぐに数字を生成するわけではありません。
シーケンスオブジェクト
数字を生成する
オンデマンド
. このオブジェクトには、開始、停止、ステップの値だけが含まれており、オブジェクトを反復するたびに、次の整数が計算されます。
また、このオブジェクトは
object.__contains__
フック
となります。
を計算します。
がその範囲に含まれる場合、その数値は 計算は(ほぼ)一定時間の操作です
*
. 範囲内のすべての可能な整数をスキャンする必要は決してありません。
の利点は
range
型は、通常のlist
またはtuple
は、レンジオブジェクトが表す範囲のサイズに関係なく、常に同じ(小さな)量のメモリを消費することです。start
,stop
とstep
の値で、必要に応じて個々の項目やサブレンジを計算します)。
そのため、最低限、あなたの
range()
オブジェクトを使用すればよいでしょう。
class my_range:
def __init__(self, start, stop=None, step=1, /):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = start, stop, step
if step < 0:
lo, hi, step = stop, start, -step
else:
lo, hi = start, stop
self.length = 0 if lo > hi else ((hi - lo - 1) // step) + 1
def __iter__(self):
current = self.start
if self.step < 0:
while current > self.stop:
yield current
current += self.step
else:
while current < self.stop:
yield current
current += self.step
def __len__(self):
return self.length
def __getitem__(self, i):
if i < 0:
i += self.length
if 0 <= i < self.length:
return self.start + i * self.step
raise IndexError('my_range object index out of range')
def __contains__(self, num):
if self.step < 0:
if not (self.stop < num <= self.start):
return False
else:
if not (self.start <= num < self.stop):
return False
return (num - self.start) % self.step == 0
これではまだ、本当の
range()
がサポートしている(例えば
.index()
または
.count()
メソッド、ハッシュ化、等値性テスト、スライスなど)がありますが、アイデアを与えてくれるはずです。
を簡略化したのも
__contains__
の実装は、整数テストにのみフォーカスしています。
range()
オブジェクトのサブクラスを含む)。
int
を使用する場合と同じように、一致する値があるかどうかを確認するために、ゆっくりとしたスキャンが開始されます。これは、たまたま整数との等値性テストをサポートしているが、整数演算もサポートすることを想定していない他の数値型をサポートし続けるために行われたものです。オリジナルの
Pythonの問題
を実装し、封じ込めテストを実施しました。
* 近く Pythonの整数は無限大なので、Nが大きくなるにつれて演算時間も長くなり、O(log N)の演算となります。これはすべて最適化されたCコードで実行され、Pythonは整数値を30ビット単位で保存するので、ここで扱う整数の大きさによるパフォーマンスの影響を見る前に、メモリを使い果たしてしまうでしょう。
関連
-
Pythonコードの可読性を向上させるツール「pycodestyle」の使い方を詳しく解説します
-
PythonによるExcelファイルの一括操作の説明
-
[解決済み】numpy: true_divide で無効な値に遭遇
-
[解決済み] 'int'オブジェクトに'__getitem__'属性がない。
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] Pythonで2つのリストを連結する方法は?
-
[解決済み] B "の印刷が "#"の印刷より劇的に遅いのはなぜですか?
-
[解決済み] Pythonで例外を手動で発生(スロー)させる
-
[解決済み】Pythonに三項条件演算子はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
python string splicing.join()とsplitting.split()の説明
-
pythonサイクルタスクスケジューリングツール スケジュール詳解
-
PyQt5はユーザーログインGUIインターフェースとログイン後のジャンプを実装しています。
-
[解決済み】ilocが「IndexError: single positional indexer is out-of-bounds」を出す。
-
[解決済み】Django: ImproperlyConfigured: SECRET_KEY 設定は空であってはならない
-
[解決済み】ImportError: bs4という名前のモジュールがない(BeautifulSoup)
-
[解決済み】Flaskのテンプレートが見つからない【重複あり
-
[解決済み】django インポートエラー - core.managementという名前のモジュールがない
-
[解決済み] 連鎖比較の簡略化
-
[解決済み] Python 2.Xのrange関数とxrange関数の違いは何ですか?