

お疲れ様です。pythonに余り触れたことのない初心者です。  
下記のプログラムについて、幾つか不明な点があるため質問させて頂きます。

  1. `randrange(len(x) - 1 )` とはどこまでの範囲なのでしょうか？  
`len(x)`とは何でしょう？-1の理由がいまいち分かりません...

  2. `random_index`とは`del_dict_items`という名の関数に`randrange`の範囲でランダムな要素を入れるという理解でよろしいのでしょうか？
  3. `except KeyError` で`setdefault`で`index`に`None`という要素を入れた時、なぜ`KeyError`が実行されるようになるのでしょうか？  
`None`を要素を入れたら辞書型の`del`は実行できる、という理解でよろしいのしょうか。

  4. `timeit.Timer` の `（）` の中の `from __main__ import random` とは何でしょう？また `t.dict` の`timeit.timer` の `（）` の `del_dict_items(x)` と `del_dict_items` の違いは何でしょう？

以上が私が理解できなかった部分です。  
お手数ですが、手助け頂ければ幸いです。

[code]

    import timeit
    import random
    
    def del_dict_items(x):
        random_index = random.randrange(len(x) - 1)
        try:
            del x[random_index]
        except KeyError:
            x.setdefault(random_index, None)
            del x[random_index]
    
    print("i\t\tlist_del_time\t\tdict_del_time")
    for i in range(100000, 1000001, 20000):
        t_list = timeit.Timer("del x[random.randrange(len(x)-1)]", "from __main__ import random, x")
        t_dict = timeit.Timer("del_dict_items(x)", "from __main__ import random, x, del_dict_items")
        x = list(range(i))
        list_del_time = t_list.timeit(number=1000)
        x = {j:None for j in range(i)}
        dict_del_time = t_dict.timeit(number=1000)
        print("%d %10.3f %20.3f" %(i, list_del_time, dict_del_time))
    
[/code]


CC BY-SA 4.0
2019-05-19T13:07:17.883
55094
2019-05-20T03:32:54.300
2019-05-20T03:32:54.300
9820
34382
question
python python3
len, random.randrange, timeit.Timerの使い方と引数の意味について


コード全体の意味がよく分からない時は、コードを分割しながら動作を調べることで意味を理解できるかもしれません。

[`len(x)`](https://docs.python.org/ja/3/library/functions.html#len)とは引数xの長さです。  
ここで扱うxはリストなので、リストに入っている要素の数を返します。

[code]

    x = [1, 2]
    print(len(x)) #2
    
[/code]

[`random.randrange(i)`](https://docs.python.org/ja/3/library/random.html?highlight=randrange#random.randrange)は0からi-1までのランダムな整数を返します。  
len(x)-1を指定するとリストの末尾の要素を削除しなくなりますが、ここで末尾を残す意図は質問文から推測できません。(`random.randrange(0,
len(x) - 1)`ならば例外を発生させないことが目的と推測できます)

[code]

    x = [1, 2]
    i = len(x) #2
    print(random.randrange(len(x)) - 1) #何度実行しても 0≦N＜(2-1) の整数(すなわち0)を返す
    
[/code]

random_indexとはdel_dict_itemsという名の関数内で有効な変数です。  
randrangeの範囲でランダムな整数を入れるという理解でよいです。

KeyErrorが実行される結果、`except
KeyError`でsetdefaultで`random_index`キーに`None`という値を入れる処理に移行します。  
setdefaultで辞書型のキーを入れれば値がNoneでも何でも辞書型のdelは実行できる、という理解でよいです。

[timeit.Timer(stmt,
setup)](https://docs.python.org/ja/3/library/timeit.html#timeit.Timer)は第1引数(stmt)に実行時間を計測するコードを記述します。第2引数(setup)に初期化するコードを記述します。  
セットアップ時に`from __main__ import random, x,
del_dict_items`を記述することで、コマンドラインから`python
hoge.py`で呼び出されるメイン関数で定義された変数`x`や関数`del_dict_items`、`random`を使えるようにしています。  
上記の記述があるので実行処理(stmt)で`del_dict_items(x)`が使用できるようになります。  
下記サンプルコードの違いとエラーに注目してください。

[code]

    # 上記の通りセットアップする
    t_dict = timeit.Timer(stmt="del_dict_items(x)", setup="from __main__ import random, x, del_dict_items")
    # セットアップ処理で「xが定義されていません」(ModuleNotFoundError: No module named 'x')エラーが出る
    t_dict = timeit.Timer(stmt="del_dict_items(x)", setup="import random, x, del_dict_items")
    # 実行処理で「del_dict_itemsが定義されていません」(NameError: name 'del_dict_items' is not defined)エラーが出る
    t_dict = timeit.Timer(stmt="del_dict_items(x)", setup="from __main__ import random, x")
    
[/code]

回答を記述していて、以下の点が気になりました。

  * 『python プログラムについて』というタイトルは抽象的なので、質問を具体的に判別できるタイトルを推奨します。(質問の幅が広くて具体化できない時は、質問を分割することが望ましいです)
  * del_deict_itemsなど、質問文の関数名に誤字が多いです。回答者が混乱するので関数や変数名の誤字には特に注意しましょう。(編集済)
  * 変数や関数の使い方があやふやになっている部分があるかもしれません。少し立ち止まってコードを分解し、理解を深めることをお勧めします。

老婆心ながら上から目線の忠告となってしまいました。  
難しいコードを例示して複数の疑問を記述するよりも、質問のスコープを絞って「単純なサンプルコードのここが分からない」と質問した方が的確な回答がつきやすい傾向にありますので、参考になさってください。


CC BY-SA 4.0
2019-05-20T02:50:29.760
55102
2019-05-20T03:26:44.250
2019-05-20T03:26:44.250
9820
9820
55094
answer


質問する前にGoogleで検索したり、ドキュメントを読んだりした上で、何が分かって何が分からないのかを記載することをおすすめします。

# `randrange(len(x) - 1 )` とは

[random.randrange](https://docs.python.org/ja/3/library/random.html#random.randrange)
のドキュメントによると、最大の値が引数、ここでは `len(x) - 1` になるようなランダムな整数を返します。

また、 [組み込み関数の
`len(x)`](https://docs.python.org/ja/3/library/functions.html#len)は、引数の要素数を返します。

ここで、 `del_dict_items` という関数では、引数として与えられた `dict` 型のランダムな要素を削除しようとしているようです。このため、
`random_index` に要素数-1のランダムな値をインデックスとして代入しているようです。

# random_indexとはdel_dic_itemsという名の関数にrandrangeの範囲でランダムな要素を入れるのか

いいえ。

コメントしたように正しくコードを記載されていないので正しく回答できませんが、少なくともこの関数の目的は要素を挿入することではなく、要素をランダムに削除することです。

# except Keyerror でsetdefaultでindexにNoneという要素を入れた時、なぜKeyerrorが実行されるようになるのか

認識されている順序が逆です。

「setdefaultでindexにNoneという要素を入れた時にKeyErrorが発生する」ではなく、「KeyErrorが発生したときにsetdefaultでindexにNoneという要素を入れる」が正しいです。

# None要素を入れたら辞書型のdelは実行できるか

はい。 `dict.setdefault` は 第一引数に対応する値があればそれを、さもなくば第二引数を値としてセットしたあとにそれを返す関数です。  
[dict.setdefault](https://docs.python.org/ja/3/library/stdtypes.html#dict.setdefault)

_そもそも`del` するからには分岐は不要で、 `x[random_index] = None` などしておけばtry-catchは不要ですが……_

# timeit.Timer の （） の中の from **main** import random とは

`__main__` は現在実行中のモジュールを指します。おそらく、このスクリプト自体を指して、それを `timeit.Timer`
から呼び出しているようです。

# t.dict のtimeit.timer の （） の del_dict_items(x) と del_deict_items の違い

`del_deict_items` という記載はなさそうです。typoでしょうか？


CC BY-SA 4.0
2019-05-20T02:54:54.347
55103
2019-05-20T03:03:45.707
2019-05-20T03:03:45.707
29826
29826
55094
answer