cocuh's note

type(あうとぷっと) -> 駄文

Pythonを最も短いコードで動かなくさせる: *a,=iter(int,1)

たぶんこれが一番短いと思います.

*a,=iter(int,1)

ちな,python3以上です.python2はもう死んだ.

解説

iter() とは

listとかをiteratorオブジェクトにするときに iter()を使うと思います.え?そもそも iter()なんて知らない…?sokka...

iter()は実は若干便利に使えます.

2. 組み込み関数 — Python 3.6.3 ドキュメント

引数が1つのときは,基本的にiterator objectに変換するための関数です.
具体的には obj.__iter__()を叩いてたりする.

iterator = iter([1,2,3])
next(iterator) # => 1
next(iterator) # => 2
next(iterator) # => 3
next(iterator) # => StopIteration

で,引数2つのときは,第一引数は呼び出し可能オブジェクト,第二引数は値である必要があります.
第二引数の値が出るまで,第一引数の呼び出し可能オブジェクトを呼び出し続けるiteratorオブジェクトになります.

class Counter:
   def __init__(self):
       self.value = 0
   def count(self):
       self.value += 1
       return self.value

c = Counter()
iterator = iter(c.count, 4)
next(iterator) # => 1
next(iterator) # => 2
next(iterator) # => 3
next(iterator) # => StopIteration

なので,次のコードとその次のコードは等価です.

c = Counter()
while True:
    value = c.count()
    if value == 4:
        break
    print(value**2)
c = Counter()
for value in iter(c.count, 4):
    print(value**2)

iter()のおかげで,短くかつ,わかりやすくなったことがわかるとおもいます.

今回はCounterという単純なものでしたが,Queueのような場合ではより便利になります.
例えば,親プロセスが queueに jobを表すdictを入れてworkerがそれを処理する.jobが Noneの場合, workerは終了する.ということを実装したい場合.

while Trueを使えば.

from queue import Queue

def worker(queue: Queue):
    while True:
        job = queue.get()
        if job is None:
            break
        process(job)

となりますが, iter()では.

from queue import Queue

def worker(queue: Queue):
    for job in iter(queue.get, None):
        process(job)

となり簡潔です.わりと便利なのでおすすめです.まぁ趣味かもしれないですけど.

で,問題のコードを見ると....

*a,=iter(int,1)

int()は常に0を返すので,ずーっと0を出力し続けるiteratorオブジェクトが iter(int,1)でできることがわかります.

Extended Iterable Unpacking

Pythonは関数で引数受け取りをlistで受け取れるのは知ってるかと思います.

def main(*args):
    print(args) # => [1,2,3]
main(1, 2, 3)

同じノリで,代入もできて便利です.

head, *tail, end = [1, 2, 3, 4, 5, 6]
print(head) # => 1
print(tail) # => [2, 3, 4, 5]
print(end) # => 6

PEP 3132 -- Extended Iterable Unpacking | Python.org

7. 単純文 (simple statement) — Python 3.6.3 ドキュメント

このとき, *tailは常にlistです.iteratorではなくlistです.つまり,iteratorを展開しています.
もし右辺が終わりのない無限iteratorであれば,無限要素を持つlistを tailに代入しようとします.

ですので,この一文で無限に0が続くlistをメモリー上に持とうとして,死にます.

*a,=iter(int,1)

知ってると便利だけど,正直使いどころあまりないpythonの仕様話でした.ちゃんちゃん.