なぜ範囲(開始、終了)に終了が含まれないのですか?


305
>>> range(1,11)

あなたにあげる

[1,2,3,4,5,6,7,8,9,10]

なぜ1-11ではないのですか?

彼らはそのように無作為にそれを行うことに決めましたか、それとも私が見ない価値があるのですか?


11
ダイクストラを読む、ewd831
SilentGhost 2010

11
基本的には、別の1セットのオフバイバグを選択します。1つのセットはループを早期に終了させる可能性が高く、もう1つのセットは例外(または他の言語のバッファーオーバーフロー)を引き起こす可能性があります。たくさんのコードを書いたら、動作の選択がrange()はるかに理にかなっていることが
わかります

32
Dijkstra、ewd831へのリンク:cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF
unutbu

35
@unutbuこのDjikstraの記事はこのトピックで頻繁に引用されていますが、ここでは何の価値もありません。人々はそれを権威への訴えとして使用しています。OPの質問に対して彼が与える唯一の関連する偽の理由は、シーケンスが空である特定の場合に上限を含むことが「不自然」で「醜く」なると彼が偶然に感じることです-それは完全に主観的な立場であり、簡単に反対されます、だからそれはテーブルに多くをもたらすことはありません。Mesaでの「実験」は、特定の制約や評価方法を知らなければ、あまり価値がありません。
sundar-2013年

6
@andreasdrしかし、表面的な議論が有効であっても、Pythonのアプローチは読みやすさの新しい問題を引き起こしませんか?一般的な用法の英語では、「範囲」という用語は何か何かから何か及ぶことを意味します。len(list(range(1,2)))が1を返し、len(list(range(2)))が2を返すことは、ダイジェストを学習する必要があるものです。
armin 2016

回答:


245

と等しい10の要素を含むrange(0, 10)whichを返す呼び出しがより一般的であるため[0,1,2,3,4,5,6,7,8,9]ですlen(range(0, 10))。プログラマーは0ベースのインデックス付けを好むことに注意してください。

また、次の一般的なコードスニペットを検討してください。

for i in range(len(li)):
    pass

これが問題になるとrange()正確に言ったなら、わかりlen(li)ますか?プログラマーは明示的に1を引く必要があります。これは、プログラマーがを優先for(int i = 0; i < 10; i++)するという一般的な傾向にも従いますfor(int i = 0; i <= 9; i++)

1から始まるrangeを頻繁に呼び出す場合は、独自の関数を定義することができます。

>>> def range1(start, end):
...     return range(start, end+1)
...
>>> range1(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

48
それが理由であるとしたら、パラメータはそうではないでしょうrange(start, count)か?
Mark Ransom 2010

3
@shogun開始値のデフォルトは0 です。つまり、range(10)と同等range(0, 10)です。
moinudin 2010

4
あなたはrange1より異なるステップサイズを持っている範囲では動作しません1
dimo414

6
range(x)は0で始まり、xは「範囲の長さ」になると説明しました。OK。しかし、range(x、y)がxで始まり、y-1で終わる必要がある理由を説明しませんでした。プログラマーがiが1から3の範囲のforループが必要な場合、明示的に1を追加する必要があります。これは本当に便利なのですか?
armin 2016

7
for i in range(len(li)):むしろアンチパターンです。使用する必要がありますenumerate
ハンス・

27

ここにはいくつかの有用なアルゴリズムの説明がありますが、なぜこれがこのように機能するのかについて簡単な「現実の」推論を追加すると役立つと思います。

「range(1,10)」のようなものでは、パラメータのペアが「開始と終了」を表すと考えると混乱が生じる可能性があります。

それは実際には開始と「停止」です。

さて、それ「終了」値である場合、そうです、その数がシーケンスの最後のエントリとして含まれることを期待するかもしれません。しかし、それは「終わり」ではありません。

他の人が誤ってそのパラメーターを "count"と呼んでいるのは、 'range(n)'だけを使用する場合はもちろん、 'n'回繰り返すからです。このロジックは、開始パラメーターを追加すると機能しなくなります。

したがって、重要な点はその名前を覚えておくことです: " 停止 "。つまり、到達したときに反復がすぐに停止するポイントです。その時点以降ではありません。

したがって、「開始」は実際に含まれる最初の値を表しますが、「停止」値に到達すると、停止する前に「その1つ」も処理し続けるのではなく、「中断」します。

これを子供たちに説明するときに使用した1つの例えは、皮肉なことに、子供たちよりも行動が良いということです。それは想定されたに停止しません-それは何をしていたかを終了することなくすぐに停止します。(彼らはこれを得る;))

別の例え-車を運転するとき、停止/降車/「道を譲る」という標識を通過せず、最終的には車の隣または後ろのどこかに座っていることになります。技術的には、停止してもまだ到達していません。「あなたが旅に出したもの」には含まれません。

その一部がPythonitos / Pythonitasの説明に役立つことを願っています!


この説明はより直感的です。ありがとう
フレッド

子供たちの説明はとっても面白いです!
アントニーハッチキンズ

1
あなたは豚に口紅をつけようとしています。「停止」と「終了」の違いはばかげています。1から7に進んだ場合、7をパスしていません。開始位置と停止位置に異なる規則があることは、Pythonの欠陥です。人間を含む他の言語では、「XからYへ」は「XからYへ」を意味します。Pythonでは、「X:Y」は「X:Y-1」を意味します。9時から11時までの会議がある場合、9時から12時、または8時から11時であると人々に伝えますか?
bzip2

24

排他的な範囲にはいくつかの利点があります。

まず、各項目range(0,n)は長さのリストの有効なインデックスですn

またrange(0,n)、長さはですが、両端を含む範囲ではありnませんn+1


18

これは、ゼロベースのインデックス付けおよびと組み合わせるとうまく機能しlen()ます。たとえば、リストに10個のアイテムがある場合x、0〜9の番号が付けられます。range(len(x))あなたに0-9を与えます。

もちろん、人々はそれを行うfor item in xか、とfor index, item in enumerate(x)いうよりPythonicicだとあなたは言うでしょうfor i in range(len(x))

スライスも同様に機能します:のfoo[1:4]1〜3のアイテムですfoo(ゼロベースのインデックス付けにより、アイテム1は実際には2番目のアイテムであることを覚えておいてください)。一貫性を保つために、どちらも同じように機能する必要があります。

私はそれを次のように考えています:「あなたが望む最初の数、その後あなたが望まない最初の数」。1〜10が必要な場合、最初の不要な数値は11なので、range(1, 11)です。

特定のアプリケーションで扱いにくくなった場合は、終了インデックスに1を追加してを呼び出す小さなヘルパー関数を書くのは簡単range()です。


1
スライスに同意します。 w = 'abc'; w[:] == w[0:len(w)]; w[:-1] == w[0:len(w)-1];
kevpie 2010

def full_range(start,stop): return range(start,stop+1) ## helper function
nobar '17

多分列挙の例はfor index, item in enumerate(x)混乱を避けるために読むべきです
ショーン

@seansありがとう、修正されました。
キンダル2016年

12

範囲の分割にも役立ちます。およびにrange(a,b)分割できますが、両端を含む範囲では、またはのいずれかを記述します。範囲を分割する必要はめったにありませんが、リストを頻繁に分割する傾向があります。これは、リストのスライスにa 番目の要素が含まれ、b番目の要素が含まれない理由の1つです。次に、同じプロパティを使用すると、一貫性が保たれます。range(a, x)range(x, b)x-1x+1l[a:b]range


11

範囲の長さは、上の値から下の値を引いたものです。

これは次のようなものと非常に似ています。

for (var i = 1; i < 11; i++) {
    //i goes from 1 to 10 in here
}

Cスタイルの言語で。

Rubyの範囲にも似ています。

1...11 #this is a range from 1 to 10

ただし、Rubyは、端末の値を含めたいことがよくあることを認識し、代替構文を提供します。

1..10 #this is also a range from 1 to 10

17
ガ!私は、Rubyを使用していないが、私はそれを想像することができます1..101...10コードを読み取るときに区別するのは難しいこと!
moinudin 2010

6
@marcog-2つのフォームが存在することがわかっている場合、違いに目を合わせる:)
Skilldrick 2010

11
Rubyの範囲演算子は完全に直感的です。長い形式では短いシーケンスになります。
ラッセルボロゴーブ2010

4
@ラッセル、たぶん1 ............ 20は1..10と同じ範囲になるはずです。これは、切り替える価値のある構文上の砂糖になります。;)
kevpie 2010

4
@ラッセル余分なドットが範囲外の最後のアイテムを圧迫します:)
Skilldrick 2010

5

基本的にpython は時間をrange(n)反復しnますが、これは排他的な性質であるため、印刷時に最後の値を与えないので、包括的な値を与える関数を作成できます。つまり、範囲で言及された最後の値も出力します。

def main():
    for i in inclusive_range(25):
        print(i, sep=" ")


def inclusive_range(*args):
    numargs = len(args)
    if numargs == 0:
        raise TypeError("you need to write at least a value")
    elif numargs == 1:
        stop = args[0]
        start = 0
        step = 1
    elif numargs == 2:
        (start, stop) = args
        step = 1
    elif numargs == 3:
        (start, stop, step) = args
    else:
        raise TypeError("Inclusive range was expected at most 3 arguments,got {}".format(numargs))
    i = start
    while i <= stop:
        yield i
        i += step


if __name__ == "__main__":
    main()

4

コードを検討する

for i in range(10):
    print "You'll see this 10 times", i

アイデアは、長さのリストを取得することですy-x。これは(上記のように)反復できます。

範囲については、Pythonのドキュメントをご覧ください。for-loop反復が主なユースケースと見なされています。


1

多くの場合、推論する方が便利です。

基本的に、我々は間の間隔と範囲を考えることができstart、およびend。の場合start <= end、それらの間の間隔の長さはend - startです。len実際に長さとして定義されている場合は、次のようになります。

len(range(start, end)) == start - end

ただし、間隔の長さを測定するのではなく、範囲に含まれる整数をカウントします。上記のプロパティをtrueに保つには、一方のエンドポイントを含め、もう一方を除外する必要があります。

stepパラメータの追加は、長さの単位を導入するようなものです。その場合、あなたは期待するでしょう

len(range(start, end, step)) == (start - end) / step

長さ。カウントを取得するには、整数除算を使用します。


Pythonの不整合に対するこれらの防御は陽気です。2つの数値間の間隔が必要な場合、間隔の代わりに減算を使用して差を取得するのはなぜですか?開始位置と終了位置に異なるインデックス付け規則を使用することには一貫性がありません。5から21の位置を取得するために「5:22」と書く必要があるのはなぜですか?
bzip2

これはPythonのものではなく、全体的にかなり一般的です。C、Java、Rubyで名前を付ける
Arseny

他の言語が必ずしもまったく同じ種類のオブジェクトを持っているということではなく、索引付けで一般的であると言う
つもりです
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.