8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SENSYAdvent Calendar 2017

Day 9

Pythonの「return 1」は必ず1を返す。そう思っていたときが僕にもありました。

Last updated at Posted at 2017-12-08

結論から書くとそんなことはなかったです。
ということで、Generator関数について勘違いしている部分があったので備忘録を兼ねて。

普通の関数

これは何の変哲も無い普通の関数です。ちゃんと1が返ってきます。

>>> def a():
...     return 1
...
>>> a()  # 実行結果は当然1
1
>>> type(a())
<class 'int'>

Generator関数

Generator関数はyieldキーワードで値を送出することでメモリ効率のいいiterableを作り出せます。

>>> def b():
...     yield 1
...
>>> b()  # 実行結果は当然generator
<generator object b at 0x106db82b0>
>>> next(b())
1
>>> type(b())
<class 'generator'>

別の関数やメソッドに渡したり、使いまわしたりする際には多少気をつかう必要がありますが、個人的にはかなり使います。

ここからが本題

さて、ここで下記は普通の関数、Generator関数どちらでしょうか。(実際にこんな感じのコードを書いてました)
また、実行結果はどうなるでしょうか。

def c(n):
    if n:
        return 1
    else:
        yield 1

実際に動かしてみました。

>>> def c(n):
...     if n:
...         return 1
...     else:
...         yield 1
...
>>> type(c(0))  # `yield 1`なのでまぁそうなるよね的な動き
<class 'generator'>

問題はこちら。
return 1だけど返り値は1じゃない!!

>>> type(c(1))  # `return 1`だけど1が返ってきていない
<class 'generator'>
>>>
>>> c(1) + 1  # 当然数値型が要求される式で使うと怒られます
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'generator' and 'int'

ちなみに yield from を使った場合でももちろん同じです。

>>> def e(n):
...     if n:
...         return 1
...     else:
...         yield from (i for i in range(9))
...
>>> type(e(0))
<class 'generator'>
>>> type(e(1))
<class 'generator'>

ということで、 return 1 って書いても1が返ってこないこともあるよという話でした。

この例ではわかりやすいように1を返しています。
が、「listかgeneratorを返す」関数を作り、その返り値を他の関数に渡すなどしていると、原因とエラーの箇所が離れてしまう非常に面倒なバグになります。
なので、正直なところ返り値の型が大きく違う関数はあまり書かないほうがいいのかなと思います。

おまけ

ちなみに実際にこういう処理が欲しい時は、こんな感じで関数自体を分けるするのがいいと思います。

>>> def _f():
...     return 1
...
>>> def _g():
...     yield 1
...
>>> def d(n):
...     if n:
...         return _f()
...     else:
...         return _g()
...
>>> d(0)
<generator object g at 0x106db8410>
>>> d(1)
1
>>> d(1) + 1
2
8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?