LoginSignup
1
2

More than 1 year has passed since last update.

初めてのPython ~コーディング編2~

Last updated at Posted at 2020-05-21

対象者

前回の記事の続きです。
本記事では前回の記事のgraph_plot.pyを元に話題をPythonのリストや条件分岐、ループ処理に移していきます。
全部すっ飛ばしても大丈夫な人は不連続な関数を描こうへどうぞ。

目次

Pythonのリスト

前回の記事では、Pythonには配列が存在しないと述べました。
その代わり、Pythonにはリスト(List)と呼ばれるデータ構造が標準搭載されています。
今回はそれについて少し触れます。

リストとは

まずリストについて簡単な説明から行います。

list_sample.py
list_sample.py
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(x)

x.append(10)
print(x)

#print(x + 3)
# TypeErrorが起こる

print(x + [3])
print(x * 3)

x = np.array(x)
print(x)
x = list(x)
print(x)

リストは配列と似た概念で、次のように用いることができます。

list_sample.py
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(x)

このxnumpy_calc.pyで定義したxと出力結果が同じになっていることに気づきましたか?
つまり、リストと配列は似たデータ構造であることがわかります。
その最大の違いはデータサイズが可変であることです。

list_sample.py
x.append(10)
print(x)

10が追加されましたね。
このappendメソッドはリスト型のデータ構造が持っている関数1で、要素を追加するためのものです。
もちろんnumpy配列で同じことをしようとしてもエラーが出るだけです。
numpyでは一度定義した配列のサイズを変更するには(内部処理で)どこかに改めてコピーする必要があります。
その点リストは予め大きめにメモリを確保することで、要素を追加する際にかかるメモリ確保の時間を節約することができます。
要するにそれぞれメリット/デメリットがあるということです。
他にもリストには要素を削除する関数などもあります。
また、リストにはnumpy配列のブロードキャスト機能はありません。

list_sample.py
#print(x + 3)
# TypeErrorが起こる

ただし次のようなことはできます。

list_sample.py
print(x + [3])
print(x * 3)

リスト同士の足し算であれば要素の追加になります。
リストと自然数の掛け算はリストそのものを数値の数だけ繰り返したリストとなります。2
その他の演算はTypeErrorが出てできません
さらに、numpy配列とリストは相互に変換もできます。

list_sample.py
x = np.array(x)
print(x)
x = list(x)
print(x)

以上で本記事で必要なリストの知識の紹介はおしまいです。
要約すると

  • リストはデータサイズが可変の配列のようなもの
  • numpyとリストは相互に変換できる

だけ知っておけば本記事ではOKです。

条件分岐とループ処理

条件分岐とは**「ある条件を満たすなら〇〇、そうでなければ××」という処理のことです。
(この処理は人間の意思決定とも似ているところがありますね)
ループ処理とは
「ある条件を満たすまで同じ処理を繰り返す」**という処理のことです。
(これは機械っぽい処理ですね)

では具体的にどのようにコードを書くのか、実際にやっていきましょう。

if

Pythonの条件分岐と言えばif文だけ3です。
C言語などをやったことのある人は「え、switchとかないの?」と思うかもしれませんね。
Pythonではswitch文の類はありません。いちいち書かなければいけません。面倒ですね。
初めての人にとっては覚えることが減ってラッキーかもしれません笑。
とりあえず、この条件分岐を使ってみましょう。

if_sample.py
if_sample.py
x = 5
if x > 0:
    # 条件式x > 0が真ならばここの処理
    print("xは0より大きいです。")
else:
    # 条件式x > 0が偽ならばここの処理
    # つまりx <= 0ならばここの処理です
    if x == 0:
        # 条件式x == 0が真ならばここの処理
        # <note>
        # ==は式の両辺が等しいか、という条件式です
        # 逆に、式の両辺が等しくないか、という演算は!=です
        print("xは0です。")
    else:
        # 条件式x == 0が偽ならばここの処理
        # つまり、x != 0ならばここの処理です
        print("xは0より小さいです。")

if x > 0:
    print("xは0より大きいです。")
elif x == 0:
    print("xは0です。")
else:
    print("xは0より小さいです。")

この二つのif文は全く同じ動作をします。
上の方はif elseのみ、下の方はif elif elseという文法を使って書いています。
見ての通りですが、if文の中にif文を書く(ネストする、といいます)ことができます。
もちろんもっとたくさんネストさせることも可能ですが、読みにくくなってしまうのでできるだけネストは少なめにするよう心がけましょう。
つまり下の方が読みやすいコードということですね。

文法まとめ

if_grammer_summary.py
if (条件式1):
    # (条件式1)が真(True)ならここに記述された処理を実行
#-----ここから-----
elif (条件式2):
    # (条件式1)が偽(False)で(条件式2)が真(True)ならここに記述された処理を実行
elif (条件式3):
...
else:
    # 全ての条件式が偽(False)ならここに記述された処理を実行
#-----ここまで-----
# 全て省略可能です。つまり最初のifだけでもOK。

for文とwhile

続いてループ処理です。
Pythonのループ処理にはforwhileの二つがあります。
二つある理由はたまに使い分けたいことがあるからですが、for文をwhile文に、while文をfor文に、等価な処理を行うように変換できますのでお好みで...と言いたいですが、基本的にfor文を使うことを個人的にオススメします。
理由は後ほど...

for

まずはfor文から。

for_sample.py
for_sample.py
for i in range(10):
    print(i)
print("----------")

for i in range(1, 10):
    print(i, end=" ")
    if i > 5:
        print("\n{} > 5".format(i))
        print("ループを抜けます")
        break
else:
    print("この文は出力されません。")

さて、上の方のfor文は0〜9まで、縦に並べて出力されます。
下の方は6までが横に並べて出力されて、「6 > 5」「ループを抜けます」と出力されて終わるはずです。
(ついでなのでいくつか紹介していない関数などを使っています。気になった方はググってみましょう。)

for文は文法を見た方がわかりやすいですね。

for_grammer_summary.py
for (変数名) in (配列やリストなど):
    (繰り返したい処理をここに書く)
else:
    (ループが正常に終了した場合の処理やループが1度も実行されなかった時に行いたい処理をここに書く)

range関数は指定された数までのリストのようなもの4を返します。
break文はループを強制的に抜けるためのものです。
for文では、**(配列やリストなど)で指定された数値が順番に(変数名)**に代入されて処理が行われます。

for_sample.pyの一つ目のループでは

  • 変数i0が代入される
  • print関数によって0が出力される
  • 変数i1が代入される
  • print関数によって1が出力される
  • ...

のように処理が進みます。

二つ目のループはfor else文の紹介のために書きました。
Pythonでは他の言語には滅多にない、ループ処理にelseを使うことができます。
elseの中には、ループが正常に終了した時に行って欲しい処理を書きます。
つまり、break文でループを強制的に終了した場合はその処理が行われません。
あまり積極的に使うことはありませんが、ネストされたfor文を全て抜けたい時などによりスッキリしたコードを書くことができます。

nested_for.py
nested_for.py
# elseあり
for i in range(10):
    for j in range(10):
        print(i, j)
        if i * j > 10:
            # i = 2, j = 6でここに入ります
            break
    else:
        continue
    break

# elseなし
flag = False
for i in range(10):
    for j in range(10):
        print(i, j)
        if i * j > 10:
            # i = 2, j = 6でここに入ります
            flag = True
            break
    if flag:
        break

continue文は以降の処理をスルーして次のループに移るためのものです。

while

次はwhile文です。

while_sample.py
while_sample.py
i = 0
while i < 10:
    print(i)
    i += 1
print("----------")

i = 0
while i < 10:
    print(i, end=" ")
    if i > 5:
        print("\n{} > 5".format(i))
        break
    i += 1
else:
    print("この文は出力されません")

このwhile_sample.pyはそれぞれfor_sample.pyと等価なループ処理となっていることが確認できると思います。
while文の文法は次の通りです。

while_grammer_summary.py
while (条件式):
    (繰り返したい処理をここに書く)
else:
    (ループが正常に終了した場合の処理やループが1度も実行されなかった時に行いたい処理をここに書く)

while文の特徴は条件式が満たされる限りループ処理をすることですね。
for文では予めループする回数が決まるのに対して、while文は不定なことがあるのが大きな違いです。
これが個人的にwhile文を使わないようにして欲しい理由につながります。

while_sample.pyの一つ目のループを以下のように変更して実行すると大量の0が出力され続けます。
<<注意>>
実行する場合は止め方をよく頭に入れておいてください。

while_sample.py
i = 0
while i < 10:
    print(i)
    #i += 1

<<止め方>>
上部の■をクリックすれば止まります。
jupyter notebookでは簡単な操作で実行を中断できるので便利ですね〜
while_error.gif

変数iの値が変わらないためにいつまでも条件式i < 10が満たされ続けてしまい、処理が無限に行われてしまうためこのようなことが発生します。
このような状況を無限ループと言います。
今回はprint関数で出力しているため異常が分かり易いですが、例えばこれが1000行のコードの中で、print関数などによる出力もない状態で発生したらどうでしょう?

一生懸命書いたコードがなぜかエラーで動かない!
ではなく
一生懸命書いたコードがエラーもないのに反応しない!

という状況になります。
初心者の頃は無限ループなんてそう簡単には気づけないためずーっと頭を悩ませることになりかねません。
以上の理由から、while文でなければ書けないようなループはまずないでしょうから、基本的にfor文を使用するようにしましょう。

不連続な関数を描こう

長くなりましたが、条件分岐とループ処理を用いて不連続な関数を書いてみましょう!
graph_plot.pyの関数fの部分を次のように変更しましょう。

graph_plot.py
# リストを用いたバージョン
def f(x):
    result = []
    for i in x:
        if i < 0:
            result.append(i + 3)
        else:
            result.append(i ** 2)
    return result
graph_plot.py
# numpy配列を用いたバージョン
def f(x):
    result = np.zeros(len(x))
    for i in range(len(x)):
        if x[i] < 0:
            result[i] = x[i] + 3
        else:
            result[i] = x[i] ** 2
    return result

こんな感じのグラフがプロットされればOKです。
discontinuous.png

めんどくさい?

めんどくさいって?間違いない。
ということでスマートな書き方も紹介しておきます。

graph_plot.py
def f(x):
    return np.where(x < 0, x + 3, x ** 2)

numpyのwhere関数は俗にいう三項演算子というやつです。
詳しくはググりましょう。
ちなみに頑張れば標準の書き方でもそれなりにスマートになります。

graph_plot.py
def f(x):
    return [i + 3 if i < 0 else i ** 2 for i in x]

リスト内包表記とif文の三項演算子を組み合わせたものですね。

list_comprehension_grammer.py
[(処理) for (変数名) in (配列やリストなど)]
ternary_operator_grammer.py
(条件式が真の時の処理) if (条件式) else (条件式が偽の時の処理)

とはいえ読みにくいし複雑です。
パッケージの偉大さがよくわかります。

初めてのPythonシリーズ記事

  1. 正確にはリスト型のクラスが持つappendメソッドです。

  2. 0以下の整数値は空のリストを返します。試してみてください。

  3. try文は条件分岐と言えなくもないです。

  4. 実際はイテレータ(ループ処理可能な)オブジェクトを返します。

1
2
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
1
2