Python3エンジニア認定基礎試験で覚えにくかった内容まとめ

f:id:monozukuri-bu:20190730100911j:plain

ふっちーです。
Python 3 エンジニア認定基礎試験目前なので、基礎を固める内容にしました。
個人的にPythonチュートリアルで忘れやすい、覚えにくいものを挙げてみました。

www.oreilly.co.jp

環境

今回もGoogle Colabolatory(Colab)を使用しました。
colab.research.google.com

スライシング

基礎的な内容ですが意外と「あれこれどうするんだっけ?」となりやすかったので、まとめておきます。
スライシングはインデックス値を範囲指定する場合に使われます。
例えば、

v_to_z = ['v', 'w', 'x', 'y', 'z']

というリストが存在し、'x', 'y', 'z'だけが欲しくなった場合を想定します。
この場合は以下のように指定できます。

v_to_z[2:5]
出力結果:
['x', 'y', 'z']

ポイントとして、終点の値は欲しい要素のインデックス値に+1した数字を指定することです。
'z'のインデックス値は4ですのでその+1である5が指定されています。
また、今回の例では'z'はリストの終点なので以下の様にも記述できます。

v_to_z[2:]

このように始点だけ決めて最後までといった範囲の決め方も可能です。
さらにもう一つ方法があります。

v_to_z[-3:]

-(マイナス)は後ろから数えた場合のインデックス値を示しています。
0から始まる正のインデックス値とは異なり、最後の要素は-1から数えるという点には注意しましょう。

最後にインデックス値が偶数番の要素だけを取り出してみましょう。

v_to_z[0:10:2]
出力結果:
['v', 'x', 'z']

始点と終点を書いた後にもう1つ数字が書かれています。
この値は始点から○個先の要素を選ぶようにしています。

例の場合は2個先なので、始点の'v'から2個先の'x'が選ばれ、さらに2個先の'z'が選ばれました。

補足として、スライシングで存在しないインデックス値を指定しても、空の結果を返すだけでエラーにはなりません。
上の例も存在しないインデックス値10まで指定してますが、動作に問題はありません。

変更可能体と変更不能

pythonには要素を変更できる変更可能体(mutable)と変更できない変更不能体(immutable)が存在します。
pythonでは以下の様に区分されています。

変更可能体 変更不能
リスト、ディクショナリ タプル、文字列、数値

先ほどの例を使って確かめてみましょう。

v_to_z[3] = 'd'
print(vtoz)
出力結果:
['v', 'w', 'x', 'd', 'z']

'y'が'd'に変更できました。
次にこのリストがタプルだった場合の動作を見てみましょう。

tuple = ('v', 'w', 'x', 'y', 'z')
tuple[3] = 'd'
TypeError: 'tuple' object does not support item assignment

「タプルは変更できません」というエラーが出てしまいました。
これによりリストは要素の変更ができて、タプルはできないという事が分かります。

しかし、数値はどうでしょう。

n = 3
print(n)
n = 8
print(n)
出力結果:
3
8

簡単に変更できてしまいました。
なぜ数値は変更不能体に分類されているのでしょうか。

この謎を解くカギは参照先アドレス(id)にあります。
参照先アドレスとは変数がどこにあるのかコンピュータに知らせるために設定される数値の事です。
変数が定義されるたびにその時に合った参照先アドレスをコンピュータが自動で決定し、その変数に割り当てます。
そして、コード等から変数が呼び出されたときは参照先アドレスを参考にその変数を見つけ、使用します。

この参照先アドレスは、id関数で見ることが可能なので上の例を使って見てみましょう。

n = 3
print(id(n))
n = 8
print(id(n))
出力結果:
10968864
10969024

同じ変数名(n)ですが、参照先アドレスが違うことが分かります。
これはn=3がn=8に変更されたのではなく、n=3とは別に新しくn=8を作ったことを意味します。
このことから、n=8はn=3に変更を加えたわけではないので、変更不能体であってもエラーにならないのです。
変更不能体とは要するに「同じ参照先アドレスの数値や要素を変更できない」と言い換えることができます。

リストで確かめてみましょう。

v_to_z = ['v', 'w', 'x', 'd', 'z']
print(id(v_to_z))
v_to_z[2] = 'k'
print(id(v_to_z))
出力結果:
140656074921096
140656074921096

まったく変わりませんね。
これで変更可能体は「同じ参照先アドレスの数値や要素を変更できる」と言いかえることができます。

引数の順番

ここでは関数...特に引数についてまとめます。

引数にはデフォルト値を設定することができます。
デフォルト値を用いることで関数を使用する際、無理に引数を入力しなくてよくなります。

しかし、デフォルト値を使って関数を定義する場合、その順番に気を付ける必要があります。

def a(b=9, c):
  pass
SyntaxError: non-default argument follows default argument

このようにデフォルト値を設定する場合はデフォルト値が設定されていない引数より前に配置することはできません。

これは関数を使用する場合も同様です。

def a(b, c=9, d=5):
  return b + c - d
  
a(c=5, 7)
SyntaxError: positional argument follows keyword argument

上の例にあるbの様な引数を位置引数、cの様な引数をキーワード引数と言います。
このキーワード引数同士には先ほどのような順番は関係ありません。

a(6, d=1, c=7)
出力結果:
12

このようにdを先に書いても大丈夫です。

おまけ 引数リストのアンパックについて

これはリストの要素1つ1つを引数の1つ1つに入れることが出来る事を意味しています。

a(*m[0])
出力結果:
7

m[0]は[1, 9, 3]なので、a(b=1, c=9, d=3)で関数を使用したことになります。

演算子の優先順位

ここでは個人的に覚えることに苦労した演算子の優先順位を取り上げます。

以下の様な関係であると語られています。

() >>> 数値演算子 >>> 比較演算子 >>> 短絡演算子

なお、各演算子には次のようなものがあります。
短絡演算子の中にも強弱があります。

名称 演算子
数値演算子 +, -, *, /, %
比較演算子 <, >, ==
短絡演算子 not > and > or

例を挙げてみましょう。

9-8 > 7
出力結果:
False

上の比較を見ると数値演算子の方が強いため、先に左辺(9-8)が評価されます。
これで左辺が1になったため1>7となり、これは間違った式なのでFalseが出力されました。

今度はこれに()を加えてみましょう。

9 - (8>7)
出力結果:
8

これは予想していませんでした...

比較では()が最も優先度が高いため8>7が先に評価されます。
この関係は正しいので、結果はTrueとなることがわかります。

すると、残りは9-Trueなので、このままでは計算できません。
しかし、ここで現れたTrueは1としても扱う仕様になっています。

if True == 1:
  print('Trueは1ニャ')
else:
  print('Trueは1じゃないワン')
出力結果:
Trueは1ニャ

このようにif文でも適用されます。

よって、9-1となり結果として8が出力されたというわけです。

printができること

print()は初心者にとって一番なじみのある関数でしょう。
ここでは普通に表示する以外にどんな機能があるかを再確認します。

end

print('hello', end=' ')のように用います。
これは表示した文字の後に続けて入力される文字などを設定することができる引数です。
デフォルトは\n(改行)が設定されています。

for i in range(8):
  print(i)
出力結果:
0
1
2
3
4
5
6
7

これがデフォルトの動きです。

for i in range(8):
  print(i, end=' ')
出力結果:
0 1 2 3 4 5 6 7 

出力ごとに' '(スペース)が入力されていることがわかります。

文字列フォーマットと組み合わせてみる

文字列のformat関数を利用することで、print文がより便利に扱えます。

print('Dirty {1} Done Dirt {0}'.format('Cheap', 'Deeds'))
出力結果:
Dirty Deeds Done Dirt Cheap

このように{}の中に入る文字列を後付けの様に設定できます。
{}に数字を入れない場合はformatの引数順に入ります。

数字だけではなくキーワード引数も入れることができます。

print('{0} love {name}'.format('I', name='you'))
出力結果:
I love you

このキーワード引数は関数と同様に位置引数よりも前に書くことはできません。
また、表示桁数も決められます。

import math
print('πは{0:.10f}です。'.format(math.pi))
出力結果:
πは3.1415926536です。

例では、小数点以下が10桁になるように表示しています。

同様のことをround関数でも行うことができます。

print('πは'+str(round(math.pi,10))+'です。')

出力結果は同じです。
%でもできます。

print('πは%.10fです。'%math.pi)

まとめ

今回は試験に向けて不安があった部分を自分の言葉でまとめました。
・スライシング
・変更可能体と変更不能
・引数の順番
・記号の優先順位
・printができること