[Work/Class/Python3の基礎とデータ処理/python_basic]

Pythonの基本と配列(list)の取り扱い

ソースコードの文字コード,拡張子

基本的にはutf-8を使用する.ソースコードファイルの一番上の行に,

# -*- coding: utf-8 -*-

と書いて文字コードを指定する.

ソースコードファイルの拡張子は一般的に「.py」である.

インデント

Pythonはインデント(字下げ)の量で,ブロック(C言語やJavaでいうところの中括弧{}で囲まれた部分)を決める.

if a == 1:
    print(a)
else:
    print('それ以外の時')

のようにする.

インデントの挿入は、「スペースを複数個入れる」操作ではなく「TABキーを1回押す」操作によってなされるべきである。

この「ブロック」という概念は,後述する制御構造の箇所で用いる.制御構造の分岐の時にはコロン「:」を付けて,その後にインデントを入れた一まとまりのプログラムを書く.

変数

変数の概念

変数とは,ある値を格納するスペースである.コンピュータでは値を扱う時にメモリ上にスペースを用意しその中に値を入れておく.そのスペースの事をプログラム上では変数と呼ぶ.

変数宣言や変数の型宣言は要らない

Pythonの変数を宣言する時に,整数型や文字列型等の型宣言は要らない.また変数であることを宣言するキーワードもない.

a = 1

だけでaという名前の整数型の変数が宣言され,1が代入される.

b = 'bの中に入れる文字列'

だとbという名前の文字列型の変数が宣言され,代入される.

print(a)
print(b)

というコードを実行すると,それぞれaという名前の変数の中身(ここでは1という整数)と,bという名前の変数の中身(ここでは「bの中に入れる文字列」という文字列)が表示される.

print(表示したい変数や文字列)で,内容を表示させる事ができる.

変数の型

「変数の型」とは,その変数が格納することができる値の種類,例えば整数(Integer),実数(プログラミングでは基本的に浮動小数点Floatとして扱う),文字列(String)などの事である.

コンピュータのメモリ上では,整数と実数(浮動小数点)では,値を格納するのに必要とするサイズが異なるため,「変数の型」という概念がある.

Pythonでは,ただの変数では変数の型(その変数が整数なのか実数なのか文字列なのか)を意識する必要はないが,今後出てくる配列や行列を扱うための事実標準となっているnumpyというライブラリでは明確に意識する必要がある.

変数を使った簡単な四則演算とその表示

a = 1
b = 2
c = a + b
print(c)

というコードは,

  1. aという変数の中に1という整数を代入
  2. bという変数の中に2という変数を代入
  3. cという変数の中に,変数aの中身と変数bの中身を足し算した結果を代入
  4. cの変数の中身を表示

という流れの処理をプログラムで書いたものである.

このように,プログラムは行単位で上から下,右から左に向けて実行される.

この + の事を演算子と呼ぶ.

四則演算の演算子は,それぞれ + が足し算, - が引き算, * が掛け算, / が割り算を表す.

四則演算以外で標準の演算子として実装されている中で,データ処理でよく使うのが,べき乗である.

b = a**2    # aの2乗

というように,演算子**を用いて記述する.(一般的にWebの表記でx^2のように「^」を用いることがあるが,これはプログラムでは使わない)

演算時の自分自身への代入

a = 1
b = 2
a = a + b

プログラムは「右から左」つまり「行末から行頭に向かって」実行される事に注意する.つまり上記のコードでは,aにはa + bの値だが移入され,3行目の実行が終わった段階では,aの中身は整数の3になっている.

Boolean

Booleanとは,論理的な「真」と「偽」を表現するための値・変数型の事を指す.後述するif文などで用いられる.

Boolean型の値はTrue, Falseである.頭が大文字になることに注意.

ifブロックやforブロックの中の変数(スコープ)

C言語やJavaとは違い,ifやforの中で新たに変数を宣言しても,その外側に変数が作られたのと同じ意味になる.つまりifやforの中の変数はそのまま保持され,外側からそのまま参照,変更することが可能である.

この変数(変数の名前)が影響を及ぼす範囲を「スコープ」と呼び,C言語やJava, PythonやRubyでは異なることに注意.

つまりPythonの変数の影響の範囲スコープは関数内が最小である.

Pythonの影響範囲スコープは,グローバルで定義した変数(プログラム全体で有効)→クラス内変数の影響(オブジェクトインスタンス内で有効)→関数内変数(関数の中で有効),の3段階である.

C言語やJavaはさらにfor文if文などのブロック内で有効,というスコープがある.

標準配列list

Pythonの標準配列はlistというクラスのオブジェクトインスタンスである.

Pythonでは宣言をしてメモリ上に確保された状態の,プリミティブな整数や浮動小数点実数以外の変数の事を「オブジェクトインスタンス」と呼ぶ.もしくは単に「オブジェクト」「インスタンス」とも.(他言語でもどちらを使うかは人によってまちまちで,同様の呼び方をする)

宣言

my_list1 = [] #listの宣言と初期化(空)
my_list2 = [1, 3, 8, 20] #listの宣言と同時に配列の中身を入れて初期化

listクラスのオブジェクトインスタンスなので,

my_list = list([1, 3, 5, 7])

のようにコンストラクタ呼び出しで生成することもできる.

というか,コンストラクタ呼び出しで生成する方がオブジェクト志向プログラミング的なので,なるべくこちらを使うように癖をつけておくこと.特にPython3ではこちらの記法を必ず使うこと.(後述のrange関数などで使われる)

listの連結

my_list = list([1, 3, 5])
new_list = list(my_list + list([7, 9, 11]))

で連結される.(結果が[1, 3, 5, 7, 9, 11]のリストになる)

list動詞の + 演算子による連結は,非破壊的,つまり足す方には影響を与えない.従って上記の場合のmy_listを更新しようと思った場合,

my_list = list([1, 3, 5])
my_list = list(my_list + list([7, 9, 11]))

のように,自分自身に代入する必要がある.

listへの追加 append関数

append関数を使うと末尾に要素が追加される.

my_list = list([1, 3, 5])
my_list.append(7)
my_list.append(9)
my_list.append(11)
print(my_list)

の結果は[1, 3, 5, 7, 9, 11]になる.

appendを使った場合,my_listそのものが更新される事に注意する.このようなlist型のオブジェクトインスタンスが持っている機能(関数)の事をインスタンス関数と呼び,再代入ではなくそのオブジェクトインスタンス自身が更新される.

listへの挿入 insert関数

my_list = list([1, 3, 5])
my_list.insert(2, 7) #insert(挿入したい場所のインデックス, 挿入したい要素)

の結果は[1, 3, 7, 5]になる.

つまりに先頭に要素を追加したい場合は

my_list.insert(0, 挿入したい要素)

となる.

listの長さを取得

len(my_list)

となる.lenはlistクラスオブジェクトの関数ではないことに注意.

range()関数で範囲指定で単調増加する整数listを生成

例えば[0, 1, 2, 3, 4]というlistを生成したい時,

my_list = list(range(5))

とすると,my_listの中には[0, 1, 2, 3, 4]というlistが入る.

my_list = list(range(3, 8))

の結果は,[3, 4, 5, 6, 7]となる.つまり「3から8未満の間に1ずつ増加させながら追加していく」のような意味となる.

2ずつ増加する整数リストを作る場合には,

my_list = list(range(3, 10, 2))

とする.結果は,[3, 5, 7, 9]である.(「10未満の場合は2ずつ増加させて追加していく」なので)

ちなみにrange()関数そのものは,listのコンストラクタに突っ込んで回すと(勝手に回ってくれる)整数の集合を生成してlistオブジェクトを作ることができる,「イテレータオブジェクト」(もしくはジェネレータオブジェクト)を返す,という仕様になっている.後述するmap()関数やfilter()関数と同じである.(Python2系はrange()関数はlistを返すので,2系と3系で一番互換性が問題となる違いである)

タプルtuple

タプル tupleという「宣言時に初期化したら変更できない」リストも存在する.

tupleの宣言には,

my_tuple = (123, 456, 789)

という形でカンマで区切った小括弧を用いる.

もしくはコンストラクタ呼び出しで,

my_tuple = tuple((123, 456, 789))

と宣言する.小括弧が二重になっていることに注意する.

my_tuple = (123, 456, 789)
my_list = list(my_tuple)
my_tuple = tuple(my_list)

という形で相互に変換することも可能である.

listと同じく,[]で囲んだ添え字で,tupleの個々の要素にアクセスすることが可能である.

my_tuple = (123, 456, 789)
print(my_tuple[2])

というコードでは,0,1,2の2番目(先頭から3つ目)の値の内容,つまり789という整数がprintされる.

ハッシュテーブル 辞書 dict

「キーと値をセットにして,キーで値を取り出せる」いわゆるハッシュテーブルはdictというクラスを使う.

my_dict = {'apple': 4, 'pine': 8, 'pen': 6}

というように,文字列と値を「:」でペアにし,間まで区切り,中括弧で囲んで宣言する.

同じくコンストラクタ呼び出しで,

my_dict = dict({'apple': 4, 'pine': 8, 'pen': 6})

とも宣言できる.

キーを与えて値を取り出すには,

value_from_dict = my_dict['apple']

と大括弧でキーを囲む.(取り出し時は中括弧ではなく大括弧であることに注意)

その他にitems()関数でキーと値のペアをイテレータオブジェクトとして取り出す,keys()関数で全てのキーをイテレータオブジェクトとして取り出す,values()関数で全ての値をイテレータオブジェクトとして取り出す,等の関数がある.

コメント

コメントとは,プログラムコードの中に記述されているが,実際には実行されない部分を指す.

Pythonの場合, # を書いた行は,#以降の部分は実行されなくなる.行頭に#を置くと,その行全体が実行されなくなる.

a = 1
b = 2
# a = a + b コメントになっているので,この行は実行されない
print(a) # 従って,ここのprintの出力は1になる

制御構造

プログラミング言語における制御構造とは,条件による分岐や繰り返しを記述するための機能である.通常「変数の中身による条件を書いて,その条件によりその後に続くブロックに分岐したり,ブロックを繰り返したりする」.

if文

if文は「もし与えられた条件が真だったら,次に続くブロックを実行する」という制御構造である.

if a == 1: # もしaが1だったら.
  # Trueの時の処理内容
  print(a)
# インデントを元に戻してブロックを終わらせて,次のプログラムへ続く

のように記述する.ブロックを始めるためには,コロン「:」が必要であることに注意.コロンが書かれた次の行からインデントを追加してブロックを始める.

条件式,比較演算子,論理演算子

上記のa == 1というのが条件式である.この条件分は先述したBoolean型を返す.つまりTrueかFalseを返す.Trueは条件が真の時に返され,Falseは条件が偽の時に返される.

条件式に使われる==などの記号を比較演算子と呼び,以下のようなものがある

a == b   # aがbと等しい場合
a > b    # aがbより大きい場合
a < b    # aがbより小さい場合
a >= b   # aがb以上の場合
a <= b   # aがb以下の場合
a != b   # aとbが等しくない場合

また複数の条件式を論理演算子と呼ばれるもので組み合わせることで,論理和(AまたはBが真の時),論理積(AかつBが真の時)を表現することができる.論理和はor(もしくは||),論理積はand(もしくは&&)で表現される.

a == b and c == d   # aがbと等しく,かつ,cがdと等しい場合
a != b or C == d   # aとbが等しくない,または,cとdが等しい場合

さらにPythonではnotという否定詞をつけることができる.

not a == b    # a == bが成立していない場合

これは厳密には,「続く条件式のTureとFalseを逆転させる」ものである.従って,not Ture都だけ書いた場合,Falseが返る.

if - else文

if文を拡張した形であり,条件が真である時には次に続くブロックを,偽である時にはelse:以降のブロックを実行する.

Pythonには中括弧によるブロック指定がないので,空のブロックを作ることができない.処理内容がないけど分岐させたい(空のブロックを作りたい)場合にはpassキーワードを必ず入れること.

if a == 1: # もしaが1だったら.
  # Trueの時の処理内容
  pass
  # passと書くとTrueの時は何もしない.
else:
  # aが1ではない時の処理内容

for文

for文は,とある条件を満たすとき,続くブロックを繰り返す制御構造である.

Pythonに通常のfor文はない.他言語でいう所の拡張for文(for_each文)のみ存在する.つまりPythonのfor文は,繰り返しを指定する「イテレータオブジェクト」の方で条件を決定した繰り返しを行い,for文側では条件判定等を行うことはない.

初学者向けに分かりやすく言えば,Pythonのfor文は「与えられたリストの要素を一つずつ取り出して,取り出した要素に対してブロック内で記述した処理を適用する」というものである.

my_list1 = list([1, 3, 5, 7, 9])
my_list2 = list([]) # 別の空のlistを作っておく
for item in my_list1:
  # my_list1から一つずつの要素(奇数の整数)を取り出し,itemという変数に格納して,続くブロックに送る.
  my_list2.append(item + 1) # ブロックの中ではitemの中の整数に1を足してmy_list2に追加する.

の結果,my_list2の中身は,[2, 4, 6, 8, 10]となる.

(他言語の学習者向け)普通にfor文を実行したい場合,つまり事前にlistを生成しない場合,前述のlist(range(0, 10, 1))でlistのオブジェクトを生成して,それをfor文に食わせることになる.

my_list = list([])
for item in list(range(0, 10, 1)):
  my_list.append(item)

の結果のmy_listの中身は[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]となる.

ちなみに食わせるのはlistだけではなく,listにする前のイテレータ(もしくはジェネレータ)オブジェクトでも構わないので

for item in range(0, 10, 1)

だけでも動作する.

ついでに,range関数の引数が一つだけの場合,前述のように「0からその数字未満まで1ずつ増加させた整数の集合」を出力してくれるので,C言語系の言語で書く所の

for(int i=0; i<10; i++){}

は,

for i in range(10):

と省略して書くことができる.

for文をindex付で取り出すenumerate

例えば,['apple', 'orange', 'grape']というlistが合って,これでfor文を回したい場合を考える.この時に「何番目か」の情報が処理の内容で欲しい時には,enumerateという機能を使う.

fluit_list = ['apple', 'orange', 'grape']
for index, item in enumerate(fluit_list):
  print(index, item)    # printの中で,をつけて変数を区切ると,区切って出力される

と書くと,何番目かを出してくれる.このlistの中の何番目かを表現する言葉として「添え字」「インデックス」という用語が用いられることが多い.

多くのプログラミング言語では,何番目かを表現するインデックスは0から始まる.