質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

4246閲覧

Pythonのassertで複数行を入出力させたいとき

mofu_mofu

総合スコア73

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2018/02/19 11:28

編集2018/02/19 11:56

お世話になっております。

競技プログラミングのような問題を解くことをPython3.6 + Pycharmで想定していて、簡単なテストをコード上で行いたいです。なのですが、複数行の入出力をassertさせる方法がわかりません。

複数行のinputやoutputをpythonでassertする方法(もしくはより簡単にPycharm上で入出力のテストができるやりかた)を教えていただけないでしょうか。

例えば、yukicoderのこの問題のサンプルとして

#input 5
#output 55555 5555 555 55 5

がありますが、以下のように書いてもassertでエラーになってしまいます。提出はできたのでmult_number関数の中身は問題ないと思われます。
(入出力はstrでされるものだと認識しています)

#num = int(input()) def mult_number(num): for i in range(0,num): print(str(num) * (num - i)) nums_4 = """ 4444 444 44 4 """ nums_5 = """ 55555 5555 555 55 5 """ assert mult_number(4) == nums_4 assert mult_number(5) == nums_5
Traceback (most recent call last): 4444 444 File "input.py", line 22, in <module> 44 4 assert mult_number(int(4)) == nums_4 AssertionError Process finished with exit code 1

よろしくお願いいたします。


追記分

#関数にしてreturnにした。WAでテストケースで引っかかった num = int(input()) def mult_number(num): for i in range(0,num): return(str(num) * (num - i))
#関数にしてprintにした。WAでテストケースで引っかかった num = int(input()) def mult_number(num): for i in range(0,num): return(str(num) * (num - i))
#関数にしていない。 テストケースをすべて通過した num = int(input()) for i in range(0,num): print(str(num) * (num - i))

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

print(...)の内容をテストしたければ以下のようにします。

python

1from contextlib import redirect_stdout 2from io import StringIO 3 4 5fp = StringIO() 6with redirect_stdout(fp): 7 mult_number(4) 8assert fp.getvalue() == nums_4

投稿2018/02/19 11:54

YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mofu_mofu

2018/02/19 12:30

YouheiSakurai様 そんなやりかたがあるのですね。ご丁寧にありがとうございます。
guest

0

ベストアンサー

nums_4は文字列ですが、mult_number(4)はNoneです。※
対話環境で同じように表示されるからと言って同値だとは全く言えないです。

Python

1>>> "aaa" 2'aaa' 3>>> print("aaa") 4aaa 5>>> 6>>> type("aaa") 7<class 'str'> 8>>> type(print("aaa")) 9aaa 10<class 'NoneType'> 11>>> 12>>> "aaa" == print("aaa") 13aaa 14False 15>>> assert "aaa" == print("aaa") 16aaa 17Traceback (most recent call last): 18 File "<stdin>", line 1, in <module> 19AssertionError

複数行の入出力をassertさせる方法がわかりません。

この場合行数は関係ないです。

※ Pythonでは、『戻り値なしの関数の戻り値』はNoneになります。ややこしい。

コメントを受けて

multi_numberを文字列を返す関数にしてみましょう。

リストを返す場合

Python

1def multi_number(num): 2 ret = [] 3 for i in range(num): 4 ret.append(str(num) * (num-i)) 5 return ret 6 7print(*multi_number(3), sep='\n') 8# 普通にfor文でぶん回しても良い 9# for row in multi_number(3): 10# print(row)

ジェネレータ関数にする場合

Python

1def multi_number(num): 2 for i in range(num): 3 yield str(num) * (num-i) 4 5for row in multi_number(3): 6 print(row)

慣れるまでは前者を使った方が分かりやすいかもしれませんね。


忘れてた。
真の意味で、文字列を返す関数

Python

1def multi_number(num): 2 ret = '' 3 for i in range(num): 4 ret += str(num) * (num-i) + '\n' 5 return ret[:-1] 6 7print(multi_number(3))

ret[:-1]したのは最後に改行が重複するのを防ぐためです。
retのまま返して、print関数の引数endに空文字列を指定するのもアリです。

投稿2018/02/19 11:35

編集2018/02/19 12:37
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mofu_mofu

2018/02/19 12:07

なるほど。print()だとNoneになってreturn("hoge")だとstrになるのですね。 追記したのですが、それとは別に関数ではないものを関数にして、それをテストしたのですが、関数でないものを関数にするときに挙動が変わっているようです。なのでこちらもおかしい原因になっているようです。 def mult_number(num): for i in range(0,num): return(str(num) * (num - i)) print(mult_number(3)) だと返り値が 333でテストケースが通らなかったです。
LouiS0616

2018/02/19 12:23 編集

ループ中にreturnしているからですね。 現状のコードでは、i=0のときに脱出してしまって二周目以降が走っていません。 yieldして呼び出し元で上手く処理するか、リストに値を貯めていって最後に返すか、どちらかを選ぶ必要があります。どちらの場合も出力に工夫が必要ですが。
mofu_mofu

2018/02/19 12:27

LouiS0616さま なるほど...yield...前にやりましたが苦手な分野できちんと理解せずに残していました。いつもご丁寧にありがとうございます。
退会済みユーザー

退会済みユーザー

2018/02/19 12:31

yieldを使ったジェネレータ式はgen = (str(num) * (num-i) for I in range(num))とも書けます。ご参考までに。
LouiS0616

2018/02/19 12:39

@dkato0077 さん 確かに、この場合ジェネレータ内包でも良いかもしれないですね。補足感謝します。 --- ついでに、文字列を返すはずの関数がリストを返していることに違和感があったのでちょっと追記しました。あまり有効活用出来ないですが。
退会済みユーザー

退会済みユーザー

2018/02/19 12:54

いえいえ、もともとの質問から外れてしまってるので単なるコメントです。使い方によっては可読性やデバッグのし易さが犠牲になりますが、競プロだと使いどころがある…かも?と思いましたので。
退会済みユーザー

退会済みユーザー

2018/02/19 12:56

余計な口出しとは思いつつ…最後の修正部分、”/n”.join()を使った方がおさまりがいいような。
LouiS0616

2018/02/19 13:18

joinで上手くいくでしょうか?
退会済みユーザー

退会済みユーザー

2018/02/19 13:22

これを試してみてください。print("\n".join(str(num) * (num-i) for i in range(num)))
退会済みユーザー

退会済みユーザー

2018/02/19 13:25

もしくはyieldを使ったバージョンのfor row in multi_number(3): print(row)をprint("\n".join(multi_number(3)))とするような形です。。
LouiS0616

2018/02/19 13:33

ああ、そちらですか。三番目の関数のお話かと思いました。 確かにジェネレータと組み合わせる場合は、joinを用いた方が簡潔かもしれませんね。
退会済みユーザー

退会済みユーザー

2018/02/19 13:35

どれを指してるのかわかりづらくてすみません。その上だんだん使い回しの出来ないネタになってきたのであくまでコメントまでにm(_ _;)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問