Edited at

筋トレで理解するPython基本の「き」

cafe_macho_tenin.png


はじめに

会社の後輩にPython3の基本について教えるための教材を準備したのですが、

思いの外好評だったので、加筆修正して投稿しようと思います。

この教材のうりは筋トレを題材にした、理解度チェックテストです。

動きを追うことが出来たらもうpythonの基本は大丈夫!というコードを作りました。

一通り説明を読み終えたら、是非試してみてください!

ベテランの方も基本の確認のために是非!


注意

あくまでPythonの文法の基本を理解するための教材です。

Pythonの文法を網羅している訳ではないのでご注意を。


進め方

出来るだけ写経しながら理解していってください。

写経する際には一語一語どのように機能しているのか考えてみましょう。

そうすることで応用力が身につきます。


最終的に読めてほしいPythonコード

macho1.pyを実行した時の流れを

追うことがきちんとできればPythonの基本はバッチリ!!

読みにくければ、お使いのエディタにコピペして読んでみて!


フォルダ構成

python_tutorial

├── macho1.py
└── macho2.py


macho1.py

import macho2

from datetime import datetime

def main(like_muscle=False):

if not like_muscle:
print("筋トレはすごいんだよ!!(怒)")
main(True)

else:
print("よく改心した。良い子だ")

start_comment = "Let's start KINTORE at {}".format(datetime.now())
muscle = macho2.Muscle(start_comment)
rewards = muscle.start_muscle_training()
print("おつかれ!!")

real_rewards = ["%s!!" % (reward) for reward in rewards]
rewards_dict = {}
rewards_dict["喉を潤す?"] = real_rewards[0]
rewards_dict["小腹を満たす?"] = real_rewards[1]

try:
1 / 0 # 無理矢理でごめんね
except ZeroDivisionError:
print("ご唱和ください")
print(rewards_dict)
finally:
print(set(["また筋トレしような!!", "また筋トレしような!!" ]))

if __name__ == "__main__":
main()



macho2.py

class ParentMuscle():

def squat(self, num):
for i in range(num):
if i == 0:
continue
print("スクワット{}回完了".format(i))

class Muscle(ParentMuscle):
"""まっする
"""

def __init__(self, start_comment):
self.start_comment = start_comment

def start_muscle_training(self):
"""筋トレをする者にご褒美を与える

Returns
-------
rewards: list of string
ご褒美のリスト
"""

print(self.start_comment)

self.push_up(3)
self.squat(2)

rewards = ["プロテイン"]
rewards.append("サラダチキン")

return rewards

def push_up(self, num):
"""腕立て伏せ
Parameters
----------
num: int
腕立ての回数

Returns
-------
なし
"""
times = 0
while times < 1000000:
times = times + 1
print(f"腕立て伏せ{times}回完了")
if times == num:
break



文法説明開始


Pythonとは


  • 少ないコード量で簡単にプログラムが書ける

  • プログラミング言語の中でも特に読みやすく、わかりやすい

  • AIやWeb開発など広い分野で利用されている

  • YouTubeやInstagramもPythonで作られている


print関数

画面に出力するprint関数の使い方は以下


print(???)


???に入るのは文字列であれば「"」もしくは「'」で囲む必要がある。

数字であればそのままでOK。


コード例

# In

print("macho")

# Out
macho



コード例2

# In

print(2)

# Out
2



変数


変数とは

プログラミングで使う変数とは、メモリ上のデータに、アクセスしやすいようにつける名前

例えば、"I love macho!!" と二回出力したい時、普通はこうなる。


コード例

# In

print("I love macho!!")
print("I love macho!!")

# Out
I love macho!!
I love macho!!


でも変数を使うと以下のようになって、記述量が減らせたり、記述が楽になったりする。


コード例

# In

ilm = "I love macho!!"
print(ilm)
print(ilm)

# Out
I love macho!!
I love macho!!



代入方法


変数名 = 値


上記のような形で変数に値を代入する。

JavaやCとは異なり、型を宣言する必要はない。

もともと文字列が入っていた変数にintなど数字の型の値を入れることも可能。

(変数に入っている値がわかりにくくなるから、変数への代入回数は少ない方が良い)


コメント


書き方

先頭に#をつける

#よりも右の文章は処理の対象にならない


コード例

# In

# print("macho")

# Out
なし


コード例

# In

print("macho") # print("macho")

# Out
macho


format

文字列の中に変数を入れたいときもある。

しかしそのまま入れてみるとダメ。


コード例

# In

favorite_fruit = "ringo"
print("I like favorite_fruit")

# Out
I like favorite_fruit


ringoではなく、変数名のfavorite_fruitが文字列としてそのまま出力されてしまった。

これを解決してくれるのが「format」

以下のような書き方で文字列の中に変数を入れることができる。


コード例

# In

favorite_fruit = "ringo"
print("I like {}".format(favorite_fruit))

# Out
I like ringo


ちゃんとringoと出力された。

2つ以上の変数を使う場合には以下のような書き方になる。


コード例

# In

first_fruit = "ringo"
second_fruit = "melon"
print("I like {} and {}".format(first_fruit, second_fruit))

# Out
I like ringo and melon



%s

formatと同じ用途で%sも使える


コード例

# In

first_fruit = "ringo"
second_fruit = "melon"
print("I like %s and %s" % (first_fruit, second_fruit))

# Out
I like ringo and melon



F-strings

formatや%s以外にも、同じ効果を持つものでF-stringsという書き方があります。

( @shiracamus さんから教えていただきました。ありがとうございます!)


>>> favorite_fruit = "ringo"
>>> print(f"I like {favorite_fruit}")
I like ringo
>>> first_fruit = "ringo"
>>> second_fruit = "melon"
>>> print(f"I like {first_fruit} and {second_fruit}")
I like ringo and melon

記述量も少ないし、読みやすいですねぇ。

format、%s、F-stringsの中ならF-stringsが一番良さそう。

F-stringsはPython3.6以降しか使えないのでご注意を。

参考サイト:PEP 498 -- Literal String Interpolation


リスト(List)


特徴

1.複数の要素(一つ一つの値のこと)を含んでいる

# In

fruits = ["ringo", "mikan", "melon"]
print(fruits)

# Out
['ringo', 'mikan', 'melon']

2.インデックス(値の順番、位置)で値を持ってこれる

# In

fruits = ["ringo", "mikan", "melon"]
print(fruits[0])
print(fruits[2])

# Out
ringo
melon

3.リストにないインデックスを指定するとエラーになる。

# In

fruits = ["ringo", "mikan", "melon"]
print(fruits[3])

# Out
Traceback (most recent call last):
File "sample.py", line 2, in <module>
print(fruits[3])
IndexError: list index out of range

4.いろんな型の要素を一つのリストに格納できる。


append

appendを使えばリストに要素を追加できる。


コード例

# In

fruits = []
print(fruits)

fruits.append("ringo")
print(fruits)

fruits.append("mikan")
print(fruits)

# Out
[]
['ringo']
['ringo', 'mikan']



ディクショナリ


特徴


  • 複数の要素を含んでいる

  • keyとvalueの組み合わせ

  • keyを指定すればvalueを持ってこれる

  • インデックスでの指定はできない

# In

address = {"country": "Japan", "city": "Tokyo"}
print(address["city"])

# Out
Tokyo

インデックスで指定しようとするとエラーになる

# In

address = {"country": "Japan", "city": "Tokyo"}
print(address[1])

# Out
Traceback (most recent call last):
File "sample.py", line 2, in <module>
print(address[1])
KeyError: 1


リストと比較したときのメリット


  • キーに文字列を入れることができるので取り出したい値を持ってくるのが楽

  • あるkey、もしくはvalueがあるか確認するときの速度、つまり検索速度が早い

  • クライアント側とやり取りするときによく使われるjsonというファイル形式と同じ書き方


デメリット


  • メモリの確保量が多い


多重ディクショナリ

ディクショナリの中にディクショナリを入れることが出来る。

# In

fruits = {"red": {"sweet": "ringo", "sour": "cherry"}, "green": "melon"}
print(fruits["red"]["sour"])

# Out
cherry


set

重複した値を持たないリストのようなもの。

「順番」という概念がないのでインデックスで要素を指定することはできない。


コード例

# In

test_set = set([1, 1, 2, 2, 3])
print(type(test_set))
print(test_set)

# Out
<class 'set'>
{1, 2, 3}


重複を削除したリストを作るときに便利


コード例

# In

test_list = [1, 1, 2, 2, 3]
set_list = list(set(test_list))
print(type(set_list))
print(set_list)

# Out
<class 'list'>
[1, 2, 3]



if文

条件分岐


書き方


if 条件式:

  条件式がTrueのときの処理


Pythonは同じ数の空白でインデントされたまとまりを一つのブロックと認識することに注意

ブロックA

if 条件文:
ブロックB
ブロックB
ブロックA

# In

a = 1
if a == 0:
print("aの値は0です")
if a == 1:
print("aの値は1です")

# Out
aの値は1です


条件式にnotがつく場合

以下のようなコードもよく見ます。

if not 条件式:

処理

この場合、条件式の結果がnotでひっくり返されますので、

条件式がfalseの時に「処理」が実行されます。

参考

# In

not_false = not False
print(not_false)

# Out
True


elif

連続でif文を使うときに使用


処理の流れ

最初の条件式がTrueのときには実行されない

スクリーンショット 2019-08-07 20.59.27.png


コード例

# In

a = 1
if a == 0:
print("aの値は0です")
elif a == 1:
print("aの値は1です")

# Out
aの値は1です



else

条件式が全部Falseだった時の処理


処理の流れ

スクリーンショット 2019-08-07 21.03.10.png

# In

a = 2
if a == 0:
print("aの値は0です")
elif a == 1:
print("aの値は1です")
else:
print("aの値は0でも1でもありません。")

# Out
aの値は0でも1でもありません


for文

繰り返し文


書き方の例

for 変数 in データのあつまり:

処理

for文は、「データのあつまり(例えばリスト)」から、「データを一つずつ取り出して」、「変数に入れる」ことを繰り返す処理。

# In

test_list = [0, 1, 2, 3]
for i in test_list:
print(i)

# Out
0
1
2
3


繰り返しの回数を指定したいとき

range関数を使う


書き方


書き方の例

for 変数 in range(繰り返したい数):

処理


コード例

# In

for i in range(5):
print("urarenge")

# Out
urarenge
urarenge
urarenge
urarenge
urarenge


ちなみにこの例の場合、iには0~4が順番に格納されて処理が行われている。


continue

その一回の処理はスキップして次の繰り返し処理に移ることを示す


書き方の例

for 変数 in データの集合体:

if ~:
continue
処理


コード例

# In

for i in range(5):
if i == 2:
continue
print(i)

# Out
0
1
3
4


iが2の時だけcontinueが実行されて、

print(i)の処理に入る前に次の繰り返しに突入していることが分かる。


break

繰り返しが終了することを示す


書き方の例

for 変数 in データの集合体:

if ~:
break
処理


コード例

# In

for i in range(5):
if i == 2:
break
print(i)

# Out
0
1


continueのときとは異なり、breakの時点で繰り返し処理が終了していることが分かる。

2重で繰り返し文が行われているときのbreak文の動きは以下。

一番内側の繰り返し文だけ抜けていることが分かる。


コード例2

# In

for i in range(3):
for j in range(2):
if j == 1:
break
print("i = {}, j = {}".format(i,j))

# Out
i = 0, j = 0
i = 1, j = 0
i = 2, j = 0



内包表記

リストを省メモリ&高速で作成出来る書き方。

リストを作成する時、出来るならfor文を使ってappendするより、

内包表記を使ったほうが良い。


書き方


コード例

変数 = [リストに格納する値 for データの集まりの一つを格納する変数 in データの集まり]



コード例

# In

naihou_list = [i for i in range(5)]
print(naihou_list)

# Out
[0, 1, 2, 3, 4]



コード例2

# In

naihou_list = [i + 1 for i in range(5)]
print(naihou_list)

# Out
[1, 2, 3, 4, 5]



コード例3

# In

naihou_list = ["a" for i in range(5)]
print(naihou_list)

# Out
['a', 'a', 'a', 'a', 'a']



while

繰り返し文の一種


書き方


コード例

while 条件式:

処理

条件式の結果がTrueなら処理が実行され続ける。


コード例

# In

i = 0
while i != 3:
print(i)
i += 1 # iの値に1を加えたものを再度iに代入

# Out
0
1
2


関数

再利用可能な処理のまとまり。


メリット


  • 記述量を減らせる

  • 関数名に適切な名前を書くことで分かりやすいコードになる。


書き方


コード例

def 関数名(引数, 引数2):

処理

関数の実行結果を格納する変数 = 関数名(パラメータ, パラメータ)


引数の数は自由に変えられる。


コード例

# In

# 関数の定義
def calc_average(num1, num2):
sum_of_num = num1 + num2
average = sum_of_num / 2
return average

# 関数の実行
ave1 = calc_average(20, 40)
ave2 = calc_average(3, 6)
print(ave1)
print(ave2)

# Out
30.0
4.5


使う頻度が高い処理はどんどん関数化しよう。


引数のデフォルト値

関数の引数にはデフォルト値を入れることが出来る。

その引数に対応するパラメータが渡されなかったときには、

デフォルト値が引数に代入されて処理が実行される。


書き方


コード例

def function_name(引数名=デフォルト値)

処理


コード例

# In

def say_something(something="りんご!!"):
print(something)

say_something("みかん")
say_something()

# Out
みかん
りんご!!



クラス

データの処理とまとまり。

基本的にインスタンス化して使う。

※クラスはあくまでも、設計図。利用するためにはインスタンス化して実体のあるものにする必要がある。

ココらへんの詳しい話に関してはオブジェクト指向でぐぐってみてね。


書き方


コード例

# クラスの定義

class クラス名():

def メソッド名1(self, 引数名):
処理
def メソッド名2(self, 引数名):
# インスタンス変数へ値を格納
self.変数名 =

# クラスからインスタンスを生成
インスタンスを格納する変数 = クラス名()

# インスタンスが持つメソッドの利用(selfに対するパラメータは送らなくても良い※)
インスタンスを格納する変数.メソッド1(引数)

# インスタンスの持つ変数の利用
インスタンスを格納する変数.メソッド2(引数) # ここでインスタンス変数を格納
インスタンスを格納する変数.変数名


※selfはインスタンス自身を示すものであり、selfという引数にはデフォルトでインスタンス自身が格納されるため。

この記事が分かりやすい:https://www.sejuku.net/blog/64106


コード例

# In

# クラスの定義
class ClassName():

def calc_avarage(self, num1, num2):

sum_num = self.calc_sum(num1, num2)
average = self.divide(sum_num)
return average

def calc_sum(self, num1, num2):

sum_num = num1 + num2
return sum_num

def divide(self, sum_num):

divided_num = sum_num / 2
return divided_num

def set_apple(self, apple):
self.apple = apple

# クラスからインスタンス生成
instance_name = ClassName()

# インスタンスの持つメソッドの利用
print(instance_name.calc_avarage(5, 10))

# インスタンスの持つ変数の利用
instance_name.set_apple("りんご")
print(instance_name.apple)

# Out
7.5
りんご


インスタンス内部から同じクラスで定義されている別のメソッドを呼ぶときには"self.メソッド名"とする。


初期化メソッド

インスタンスを生成すると同時にインスタンス変数に初期値を入れることが出来る。


書き方


# クラスの定義
class クラス名():

def __init__(self, 引数名):
self.インスタンス変数名 = 引数名

# クラスからインスタンスを生成
インスタンスを格納する変数 = クラス名(パラメータ)

# インスタンス変数の利用
インスタンスを格納する変数.インスタンス変数名


コード例

# In

# クラスの定義
class Yone():

def __init__(self, favorite_fruit_and_song):
self.fruit_and_song = favorite_fruit_and_song

def say_favorite_fruit_and_song(self):
print(self.fruit_and_song)

# クラスからインスタンス生成
yone = Yone("lemon")

# インスタンスの持つメソッドの利用
yone.say_favorite_fruit_and_song()

# Out
lemon



継承

別のクラスの変数とメソッドを引き継ぐこと


書き方の例


# クラスの定義
class クラス名1():
def メソッド名(self, 引数名):
処理

# クラスの定義
class クラス名2(継承するクラス名):
def メソッド名(self, 引数名):
処理

# クラスからインスタンスを生成
インスタンスを格納する変数 = クラス名2()

# 継承したクラスのメソッドを利用
インスタンスを格納する変数.クラス1のメソッド



コード例

# In

# クラスの定義
class Parent():

name = "parent"

def say_parent(self):
print("I am parent")

# クラスの定義
class Child(Parent):
def say_am_i(self):
print("I am child")

# クラスからインスタンスを生成
child = Child()

# 継承元クラスの変数利用
print(child.name)

# 継承元クラスのメソッド利用
child.say_parent()

# 自分のクラスのメソッド利用
child.say_am_i()
# Out
parent
I am parent
I am child


継承元クラスのことを親クラス、継承をしている方のクラスを子クラスと読んだりする。


docString

関数、クラス、メソッドにつける説明文。

多くのフォーマットがあるけど私がよく見るのはNumpyスタイルなので、Numpyスタイルを元に説明。

他にはGoogleスタイルなんてのもある。

docStringがあるとコードの可読性が上がるので忘れずに!


書き方の例

def 関数名(引数):

"""関数内容の要約

詳細:

Parameters
----------
引数 : 型
引数の説明

Returns
-------
戻り値 : 型
戻り値の説明
"""
~処理~
return 戻り値



コード例

def eat_fruit(fruit):

"""果物食べる

引数として渡された果物を食べて残骸を返すよ:

Parameters
----------
fruit : string
果物の名前

Returns
-------
zangai : string
食べ終わったあとの残骸だよ
"""
# ~処理~
return zangai



import文

Pythonではimport文を使うことで標準ライブラリやパッケージ、自作のファイルなどを利用することが出来る。

ライブラリやらパッケージやらの説明は大変なので以下のサイトに丸投げ。(ごめんね。)

https://note.nkmk.me/python-import-usage/


try-except

pythonの例外処理。

日本語での説明は難しいので、以下のコード例をとりあえずどうぞ。

try:

例外が発生するかもしれない処理
except エラー名: # エラー名は省略が可能。その場合はすべてのエラーをキャッチする
例外発生時に行う処理

以下引用:https://www.sejuku.net/blog/23044


まずは、tryの中に指定された処理が実行されます。例外が発生しなければ、except文はスキップされます。

しかし、try実行中にexceptキーワードの後に指定したエラー名と一致する例外が発生すると、except文が実行され、それ以降に記述された処理も実行されます。

このように「except」ブロックで例外を捉えて処理をすることで、エラー発生箇所で処理が停止することはありません。



使いどころ


  • エラーが発生しても絶対に処理を続けたい時

  • 標準で出力されるエラー文に更に情報を追加したい時

絶対に処理を続けたいとき、エラー処理をしなかった場合


コード例

# In

print(1 /0)
print("絶対に出力したい文字列")
# Out
Traceback (most recent call last):
File "sample.py", line 1, in <module>
print(1 /0)
ZeroDivisionError: division by zero

エラーが発生してしまった。

絶対出力したかった文字列は表示されていない。

次が例外処理をした場合のコード例


コード例

# In

try:
print(1 /0)
except ZeroDivisionError:
pass
print("絶対に出力したい文字列")

# Out
絶対に出力したい文字列


絶対に出力したい文字列が表示された!


finally

try句内でエラーが起きたとしても起きなかったとしても、

最終的に実行される文を指定するのがfinally


コード例

# In

try:
1 /1
print("exceptしませんでした。")
except ZeroDivisionError:
print("exceptしました。")
finally:
print("finally句")

# Out
exceptしませんでした。
finally



コード例

# In

try:
print(1 /0)
except ZeroDivisionError:
print("exceptしました。")
finally:
print("finally句")

# Out
exceptしました。
finally


ちなみにexcept句でエラーが発生してしまってもfinallyの処理は実行されるよ。


コード例

# In

try:
1 / 0
print("exceptしませんでした。")
except ZeroDivisionError:
print("exceptしました。")
raise # raiseはtryで発生した例外を再度発生させる関数
finally:
print("finally句")

# Out
exceptしました。
finally
Traceback (most recent call last):
File "sample.py", line 2, in <module>
1 / 0
ZeroDivisionError: division by zero


finally句が表示されていることが確認できる。


if __name__ == "__main__":


__name__

__name__という変数は宣言をしなくてもどんなファイルにも存在する。

この変数には基本的に拡張子なしのファイル名が保存される。

しかし、__name__が記述されたファイルが直接実行された時のみ"__main__"という文字列が入る。


実行例

以下の構成の場合

name

├── name1.py
└── name2.py


name1.py

import name2

print(__name__)
name2.print_name()



name2.py

def print_name():

print(__name__)

name1.pyを実行するとこうなる。

$ python3 name1.py

__main__
name2

name1.pyは直接実行されているファイルなので、name1.pyの行3では__main__が出力される。

name2.pyは直接実行されていないファイルなので、name2.pyの行2ではファイル名が拡張子なしで出力されている。

以上のことを踏まえてif __name__ = "__main__":の使い方

if __name__ == "__main__":

この記述がされているファイルが直接実行されたときのみ実行したい処理


まとめ

ここまで読んでくれてありがとう!

文法の説明をちゃんと理解したと思ったら最初のマッチョファイルを読み進めてみてね!

ちゃんと流れを追うことができれば、君も、パーフェクトパイソニア