😸

Pythonの勉強メモ

2023/09/04に公開

内容について

Pythonを基礎から勉強するためにPythonプログラミング入門を読んで気になったところや他の知っている言語(PHP等)との違いをメモ

数値演算

  • ** と指定すると指数になる(ex:4 ** 2 = 16)
    • PHPは5.6以降で同じ書き方ができる(知らなかった)
    • PHP5.6未満の場合はpow(4, 2)と書く
  • // で割ると切り捨てとなる(ex:7 / 2 = 3.5だが7 // 2 = 3となる)
    • PHPの場合はfloor(7 / 2)

変数と関数の基礎

  • 関数定義はdef 関数名 (引数, ...):という形式になる。
  • 中括弧({})で括らないが、インデントをつけることで構文を定義
def bmi(height, weight):
    return weight / (height/100.0) ** 2
  • print関数は画面に出力する関数で他の言語と同じだが、任意個の引数を取ることができて,の区切りには空白文字が出力される。
    • 例えばprint('a','b','c')a b cと出力される

論理・比較演算と条件分岐の基礎

  • if else も中括弧で括らずにインデントで構文を定義し、インデントの前は:を指定
def bmax(a,b):
  if a > b:
    return a
  else:
    return b
  • true は True、 false は False、null は None
    • true,falseの先頭は大文字であるが、nullはNoneと違うことに注意

テストとデバッグ

  • コーディングスタイルはPython では PEP8(非公式日本語訳)と呼ばれる公式のスタイルガイドがある
  • 代表的なものとして次のようなものがある
    • インデントは半角スペースを 4 つで 1 レベル
    • = += == などの演算子の前後に半角スペースを 1 つ入れる
      • と + の複合式では + の前後に半角スペースを 1 つ入れる(例:2*x + y)
    • 関数の開き括弧の前にスペースを入れない
    • l I O を変数名として使わない
    • 真理値の比較に == や is を使わない

文字列 (string)

  • indexを指定すると指定文字を取得できる(ex:hello[2]と指定するとlを取得`)
  • 部分文字列(substrやsubstring)の取得について
    • いわゆるsubstrはstr[1:4]のように書く(この場合はindex1から4未満の文字を取得)
    • str[:4]str[1:]のように省略することも可能
    • マイナスも書けてその場合は後ろから指定(str[-3:-1]は-3番目から最後までの指定)
    • str[1:5:2]というのも書けてこの場合はindex1〜4の文字を2つおきに取得するのでこの場合はindex1,3の文字が取得できる
    • 3番めの文字列を-1とすることもできこの場合は後ろから取得する(ex:digits='0123456789'に対してdigits[8:4:-1]とすると'8765'となる)
      • 【補足】digits[9:0:-1]と指定すると'987654321'となるが、digits[9:-1:-1]はエラーで最後の0が取得できないのでどう指定しても'9876543210'にはならないと思う。
  • シングルクォート(もしくはダブルクォート)で、何も囲まない場合、長さ 0 の文字列(空文字列(くうもじれつ)もしくは、空列(くうれつ))となります。と書いているが本当?
    • 自分は「からもじれつ」といつも読んでいる
  • 文字列検索(in演算子, indexメソッド, findメソッド)について
    • PythonにはTrue,Falseを返す文字列検索がある
      • 例えば'lo' in 'hello'だとTrueとなり'z' in 'hello'だとFalseとなる
    • 文字列の場所を指定するにはindexやfindを用いる。
      • 例えば'hello'.index('l')'hello'.find('l')だと2となる
      • indexfindは検索文字が見つからなかった時に違いあり、前者だとエラーで後者だと-1となる。
        • PHPのstrposと機能が近いがstrposは検索文字が見つからないとfalseを返すのでどちらとも異なる
  • 文字列の連結について
    • 文字列の連結はJavascriptと同様で+で連結する
      • PHPの場合は.で連結
    • 他の言語と違う?ことしては文字列に*で回数を指定すると繰り返し文字となる
    • 例えば下記の結果はhellohellohelloとなる
word = 'hello'
word * 3
  • 空白文字の削除について
    • 空白文字の削除は文字列.strip()とする
      • 例えば' abc\n'.strip()abcとなる
        • PHPのtrimと同等の機能
    • 左だけ削除するlstrip()や右だけ削除するrstrip()もある
      • PHPのltrimrtrimと同様
  • 文字列のメソッドについて
    • 上記で上げたもの以外に例えば以下のようなメソッドがある(他にも多数あるはず)
      • replace()は文字列を置換するメソッド
      • lower()は小文字に変換するメソッド
      • capitalize()は先頭を大文字に変換するメソッド
      • upper()は大文字に変換するメソッド
  • 文字列の比較について
    • ==,!=,<,>等が使えるので基本は他の言語とは変わらないが、文字列の大小の比較は辞書式による比較で、文字列の最初の文字から順に比較して大小を決定する
      • 例えば'abc' < 'abd'はTrueになる。
    • また、片方がもう片方を拡張したものであれば、拡張した方を大きいとする。
      • 例えば'ab' < 'abc'はTrueになる。

リスト (list)

  • listの場合も部分文字列の取得と同じ書き方でlist[1:4]と書くとindex1〜3までの要素が取得できる
  • listにも様々な関数やメソッド(メソッドは後述)がある
    • len(list)でリストの要素数を返す
    • max(list)でリストの最大値を返す
    • min(list)でリストの最小値を返す
    • sum(list)でリストの合計値を返す
      • 【補足】リスト内に文字列があるとエラーっぽい
  • 文字列と同様に*で回数を指定することができる
    • これは配列の初期化で利用すると便利
      • 例えばzero10 = [0] * 10とするとzero10は0の値が10個入ったリストになる
    • 繰り返しは多次元配列でも可能
      • 例えばx=[[0, 1], [2, 3]]とするとy=x*3y[[0, 1], [2, 3], [0, 1], [2, 3], [0, 1], [2, 3]]になる
      • ただし、これは[[0, 1], [2, 3]]というものを3つ入れるのと同じであることに注意(要するにポインターを入れている?)
      • つまりx[0][0]=99とするとy[[99, 1], [2, 3], [99, 1], [2, 3], [99, 1], [2, 3]]になる。(xの元の値を変更したから)
  • in演算子について
    • listの場合も文字列と同様にin演算子でTure/Falseの存在チェックをすることができる。
      • 例えばnumbers=[0, 10, 20]に対して10 in numbersTrueとなる
      • これを逆に考えるとa == 1 or a == 3 or a == 7a in [1, 3, 7]と書ける
    • in演算子はリストの長さが長いほど時間がかかるのに注意が必要
    • in演算子の反対のnot inもある
    • 【補足】今回は数字で例を上げているが文字でも同じようにできる
  • 指定した要素のインデックス取得と数えあげ
    • list.index(値)で値のindex値を取得できる
      • 【補足】値が存在しない場合はエラー、複数存在する場合ははじめに取れたindex
    • list.count(値)で値の個数を取得できる
  • 並び替え
    • list.sort()でlistの中を昇順で並び替える
      • 【補足】数値、文字の両方で並び替えはできるが、数値/文字の混在の場合はエラー
      • 【補足】文字の場合は文字列の比較と同じく文字列の最初の文字から順に比較して大小を決定、同じ場合は次の文字で比較となる。
    • list.sort(reverse = True)とすると降順で並び替えになる
    • sorted 組み込み関数もあってsorted(list)で利用できる
      • 【補足】メソッドの場合は自分自身がソートされるが関数の場合はソートした値が戻ってくるという違いがある
      • 【補足】sortメソッドと同じく数値/文字の混在の場合はエラーだし、文字列のソート判断も同じ
    • sorted(list, reverse=True)とすると降順で並び替えになる
    • 多重リストのソートはindex0でソート(想像どおり?)
  • 並び替え例
char = ["bb", "a", "aa", "ba", "ab", "b"]
sorted(char)
結果:['a', 'aa', 'ab', 'b', 'ba', 'bb']
char
結果:["bb", "a", "aa", "ba", "ab", "b"]
char.sort()
char
結果:['a', 'aa', 'ab', 'b', 'ba', 'bb']
lns = [[20, 5], [10, 30], [40, 20], [30, 10]]
lns.sort()
lns
結果:[[10, 30], [20, 5], [30, 10], [40, 20]]
  • リストの操作
    • list.append(要素)で最後に要素を追加
    • list.extend(other_list)でlistの最後にother_listを追加
    • list.insert(index, 要素)でindexの場所に要素を追加
    • list.remove(要素)で要素を削除
      • 複数存在する場合は最初の要素を削除
      • 要素が存在しない場合はエラー
    • list.pop(index)でindexで指定した要素を削除。戻り値としてその要素が返ってくる
      • indexを指定しない場合は最後の要素を削除
    • del list[index]でindexの要素を削除
      • sortと違い、list.removeもdel listも自分自身のリストから削除
    • del list[x:y]でlistの一部分を削除(indexがxからy未満の値を取得してdelで削除と考えるとわかりやすい?)
    • list.reverse()とすると要素を逆順にする
    • list.copy()でlistの値をコピー(shallow copy)
    • shallow copyは元のオブジェクトの中はオブジェクトの参照が渡される
    • 完全にコピーしたい場合はcopyモジュールのdeepcopy()関数を使う

【注意】 copyをした場合は元のlistに影響はないがlistを直接代入する場合は参照渡しと同じなので元にlistに影響がある。

numbers = [10, 20, 30, 40, 50]
numbers2 = numbers
del numbers[1:3]
numbers.reverse()
print(numbers)
print(numbers2)
---
[50, 40, 10]
[50, 40, 10]

【注意】 オブジェクトの代入とshallow copyとdeep copy

import copy

l = [0, 1, [2, 3]]
l_assign = l                   # assignment
l_copy = l.copy()              # shallow copy
l_deepcopy = copy.deepcopy(l)  # deep copy

l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]

print(l_assign)
# [0, 100, [200, 3]]

print(l_copy)
# [0, 1, [200, 3]]

print(l_deepcopy)
# [0, 1, [2, 3]]
---
[0, 100, [200, 3]]
[0, 100, [200, 3]]
[0, 1, [200, 3]]
[0, 1, [2, 3]]
  • リストと文字列の相互変換

    • list('文字列')で文字列をlistに変換
      • list('abc123')だと ['a', 'b', 'c', '1', '2', '3']
    • 文字列.split('文字')で文字を分割
      • 'banana'.split('n')だと['ba', 'a', 'a']
    • joinで文字列→listの変換の逆バージョン
      • 上記2つの例では''.join(['a', 'b', 'c', '1', '2', '3'])で'abc123'となり'n'.join(['ba', 'a', 'a'])で'banana'となる
  • タプル (tuple)

    • タプルとは簡単に言うとデータ変更不可なlist
    • リストは[]で囲うがタプルは()で囲う。
      • ()なしでもtuple = 1,2,3のように,で分ければtupleは(1,2,3)というタプルになる
      • ()とすれば空のタプルも作成できるが、(1)とすると1になるので要素が1つのタプルを作る場合は(1,)とする
        • 変数の戻り値などで利用するときにいくつ戻るかわからないときは注意が必要かも
    • listと同じくtuple[index]で要素を取得
    • listと同じくlen(tuple)でtupleの要素数を取得
    • listと同じくtuple[1:4]と書くとindex1〜3までの要素が取得できる
    • list(tuple)とするとtuple→listへの変換ができる
    • tuple(list)とするとlist→tupleへの変換ができる
  • 多重代入

    • 複数の値を一気に代入が可能
      • [1,2,3]をlistとしたとき、(x,y,z)=listと書くことができる。x,y,z=listと書いても同じ
      • "123"をstrとしたときも同様にx,y,z=strと書くことができる
      • (1,2,3)をtupleとしたときも同様にx,y,z=tupleと書くことができる
      • 上記3つは全て共通でx=1,y=2,z=3となる
      • 変数の初期化などでx,y,z=1,2,3とかける
    • listの大小比較は文字列と同じと考えて良い
  • for文

    • for文は基本的に for value in list:の書き方になる
      • for(i=0;i<10;i++)のような書き方はない?
    • [x を含む式 for x in リストを返す式]という1行で書く書き方もある
    • 例えば次の2つは同じ書き方
numbers = [0,1,2,3,4,5]
squares1 = []
for x in numbers:
squares1.append(x**2)
squares1
---
 [0, 1, 4, 9, 16, 25]
squares2 = [x**2 for x in numbers]
squares2
---
 [0, 1, 4, 9, 16, 25]
  • オブジェクトの同一性の確認はisで確認できる
    • オブジェクトが同一の場合は参照渡しされているのと同じなので他方に値を入れると両方に同じものが入る
a = []
b = []
a is b
---
False

否定はis not

a is not b
---
TRue

条件分岐

  • if … elif … else という構文になる
    • if … elseif … else ではないのに注意
  • ifの条件文が複数行になる場合は()でくくるか改行のところでバックスラッシュ(\)を入れる
### 丸括弧で括る方法
x, y, z = (-1, -2, -3)
if (x < 0 and y < 0 and z < 0 and
    x != y and y != z and x != z):
    print('x, y and z are different and negatives.')
### 行末にバックスラッシュ(\) を入れる方法
x, y, z = (-1, -2, -3)
if x < 0 and y < 0 and z < 0 and \
    x != y and y != z and x != z:
    print('x, y and z are different and negatives.')
  • 条件の論理積はandで論理和はorとなる。
    • PHPの場合は論理積は&&で論理和は||
  • 3項演算子は次のように書く
x = 0
sign = 'positive or zero' if x >= 0 else 'negative'
print(sign)
---
positive or zero

辞書 (dictionary)

  • 配列の値確認はin演算子を使う
    • PHPではin_array関数
ppap = {'apple': 3, 'pen': 5}
'apple' in ppap
---
True
  • 要素数を取得するのはlen
    • PHPではcount関数
ppap = {'apple': 3, 'pen': 5}
len(ppap)
---
2
  • 要素の削除はdel文、popメソッド
    • PHPの場合はunset関数
ppap = {'apple' : 3, 'pen' : 5}
del ppap['pen']
print(ppap)
ppap.pop('apple')
print(ppap)
---
{'apple': 3}
{}
  • キーを指定して値を取得する場合
    • ppap['orange']のように[]指定だとキーがないとエラー
    • ppap.get('orange')のようにgetで指定するとエラーにならずNoneが返る
    • ppap.get('orange', -1)のように第二引数に値を指定するとエラー時に指定した値が返る
    • setdefaultを指定すると値がないときにデフォルト値を登録してくれる
ppap = {'apple' : 3, 'pen' : 5}
print(' キー apple に対応する値 = ', ppap.get('apple'))
print(' キー orange に対応する値 = ', ppap.get('orange'))
print(' キー apple に対応する値 = ', ppap.get('apple', -1))
print(' キー orange に対応する値 = ', ppap.get('orange', -1))
print(' キー orange に対応する値(エラー) = ', ppap['orange'])
---
 キー apple に対応する値 =  3
 キー orange に対応する値 =  None
 キー apple に対応する値 =  3
 キー orange に対応する値 =  -1
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-1-88509f3b2cf6> in <cell line: 6>()
      4 print(' キー apple に対応する値 = ', ppap.get('apple', -1))
      5 print(' キー orange に対応する値 = ', ppap.get('orange', -1))
----> 6 print(' キー orange に対応する値(エラー) = ', ppap['orange'])
      7 

KeyError: 'orange'
ppap = {'apple' : 3, 'pen' : 5}
print(' キー apple に対応する値 = ', ppap.setdefault('apple', 7))
print('setdefault("apple", 7) を実行後の辞書 = ', ppap)
print(' キー orange に対応する値 = ', ppap.setdefault('orange', 7))
print('setdefault("orange", 7) を実行後の辞書 = ', ppap)
---
キー apple に対応する値 = 3
setdefault("apple", 7) を実行後の辞書 = {'apple': 3, 'pen': 5}
キー orange に対応する値 = 7
setdefault("orange", 7) を実行後の辞書 = {'apple': 3, 'pen': 5, 'orange': 7}
ppap = {'apple' : 3, 'pen' : 5}
ppap.setdefault('apple', 7)
ppap.setdefault('orange', 7)
print(ppap)

### 上と下は同じことをしている

ppap = {'apple' : 3, 'pen' : 5}
if 'apple' not in ppap:
    ppap['apple'] = 7
if 'orange' not in ppap:
    ppap['orange'] = 7
print(ppap)
---
{'apple': 3, 'pen': 5, 'orange': 7}
{'apple': 3, 'pen': 5, 'orange': 7}
  • すべてのキーと値を削除するのはclearメソッド
ppap = {'apple' : 3, 'pen' : 5}
ppap.clear()
ppap
---
{}
  • キーの一覧を取得するのはkeysメソッド
    • PHPではarray_keys関数
ppap = {'apple' : 3, 'pen' : 5}
list(ppap.keys())
---
['apple', 'pen']
  • 値の一覧を取得するのはvaluesメソッド
    • PHPではarray_values関数
list(ppap.values())
---
[3, 5]
  • キーと値の一覧を取得するのはitemsメソッド(戻り地はタプルの配列)
    • PHPでは対応するものがないかも
list(ppap.items())
---
[('apple', 3), ('pen', 5)]
  • 辞書の複製にはcopyメソッドを用いる
    • =での代入は参照渡しなので注意
    • PHPだとa=bがcopyメソッドにあたり、参照渡しの場合はa=&bとなる
  • keys、values、itemsの各メソッドはすべて参照渡しなので一つの値が変わると全て変わる
ppap = {'apple': 3, 'pen': 5, 'orange': 7}
ks = ppap.keys()
vs = ppap.values()
itms = ppap.items()
print(list(ks))
print(list(vs))
print(list(itms))
ppap['kiwi'] = 9
print(list(ks))
print(list(vs))
print(list(itms))
---
['apple', 'pen', 'orange']
[3, 5, 7]
[('apple', 3), ('pen', 5), ('orange', 7)]
['apple', 'pen', 'orange', 'kiwi']
[3, 5, 7, 9]
[('apple', 3), ('pen', 5), ('orange', 7), ('kiwi', 9)]

繰り返し

  • 他の言語と違い、繰り返し元は文字列でも可能。文字列の場合は一文字ずつ処理される
word = 'apple'
for c in word:
  print(c)
---
a
p
p
l
e
  • ord関数で文字のASCIIコードが取得でき、chr関数でASCIIコードを文字コードに変換する
    • ordとchrともにPHPも同じ関数がある
print(ord('a'))
print(ord('b'))
print(ord('z'))
print(chr(97))
---
97
98
122
a
  • dictionaryに対してforで回すとkeyが取得できる=keys関数で回すのと同じ
    • 他にvaluesで回すと値で指定でき、itemsで回すとkey,valueの両方で回す
  • 【注意】PHPではdictionaryを直接foreachで指定するとvaluesの値が取れるが、pythonはkeysの値がとれるという違いあり
dic1 = {'cat': 3, 'dog': 5, 'elephant': 8}
for key in dic1:
  print('key:', key, ', value:', dic1[key])
for value in dic1.values():
  print('value:', value)
for key, value in dic1.items():
  print('key:', key, 'value:', value)
---
key: cat , value: 3
key: dog , value: 5
key: elephant , value: 8
value: 3
value: 5
value: 8
key: cat value: 3
key: dog value: 5
key: elephant value: 8
  • range関数を使うと特定の回数の繰り返し処理ができる
    • PHPのrangeとは微妙に違うかも
    • 引数を1つ渡すと0から引数までの整数列を返す
    • 2つ以上渡すとstartとstop値を返す
    • 3つ渡すとstartとstopとstep値を返す
### 
# ln = 'edacfb'としても結果は同じ
ln = ['e', 'd', 'a', 'c', 'f', 'b']
for value in range(len(ln)):
  print(ln[value])
---
e
d
a
c
f
b
# range(4)はrange(0, 4)と同じであり、range(0, 4, 1)と同じ
for value in range(4):
  print(value)
print("--")
for value in range(0, 4, 2):
  print(value)
print("--")
for value in range(1, 4, 2):
  print(value)
---
0
1
2
3
--
0
2
--
1
3
  • range関数は整数列を返すがリストを返すわけではない。
    • リストを返したい場合はlist関数で明示的にリスト化する必要がある。
print(range(5))
print(list(range(5)))
seq_list = list(range(5))
print(seq_list)
---
range(0, 5)
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
  • forの他にwhileもあり
    • 関数を抜けるreturnやループを抜けるbreak、ループを飛ばすcontinueもある
x = 1
total = 0
while x <= 10:
  total += x
  x += 1
print(x, total)
### 上と下はほぼ同じ(xの値は異なる)
total = 0
for x in range(11):
  total += x
print(x, total)
---
11 55
10 55
  • for文やwhile文にはelseをつけれてelseをつけるとループの最後に一度だけ実行
    • breakをするとループから抜けるのでelseも実行されない
colors = ['red', 'green', 'blue', 'black', 'white']
for c in colors:
  if c == 'black':
    continue
  print(c)
else:
  print('end')
---
red
green
blue
white
end

関数

  • 関数定義の一般形は以下の通り
def 関数名 (引数):
  関数本体
  • 関数内のローカル変数とグローバル変数を同じ名前で使うには注意が必要
    • 関数内でローカル変数の定義があるとその関数内はどこでもローカル変数となる
      • 普段はそんなことをしないと思うが
    • 次の例はエラーになるもの
greeting_global = 'Hello'
def greeting():
  print(greeting_global) # 最初の参照
  greeting_global = 'Bonjour' # ローカル変数の定義
  print(greeting_global)
greeting()
---
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-7-8c1b3cc579e8> in <cell line: 6>()
      4   greeting_global = 'Bonjour' # ローカル変数の定義
      5   print(greeting_global)
----> 6 greeting()

<ipython-input-7-8c1b3cc579e8> in greeting()
      1 greeting_global = 'Hello'
      2 def greeting():
----> 3   print(greeting_global) # 最初の参照
      4   greeting_global = 'Bonjour' # ローカル変数の定義
      5   print(greeting_global)

UnboundLocalError: local variable 'greeting_global' referenced before assignment
  • global宣言をすれば関数内でもグローバルでアクセスできる
#グローバル変数 greeting_global に値を代入する関数 greeting
def greeting():
  global greeting_global
  greeting_global = 'Bonjour'
  print(greeting_global)
greeting()
##変数 greeting_global
greeting_global
---
Bonjour
'Bonjour'
  • 引数名を指定して関数を呼び出すことができる。
#文字列と数値を引数として受け取る関数 greeting
def greeting(en, number, name):
  print(en*number+','+name)
#関数 greeting に引数の変数名とその値の組みを渡して呼び出し
greeting(en='Hello', name='Japan', number=2)
#位置引数とキーワード引数を組み合わせた関数 greeting の呼び出し
greeting('Hello', name='Japan', number=2)
---
HelloHello,Japan
HelloHello,Japan
  • 引数の初期値を指定して省略することもできる
#引数の初期値(引数の変数 en に対する'Hello')を持つ関数 greeting
def greeting(name, en='Hello'):
  print(en+', '+name)
#引数の初期値を持つ関数 greeting の呼び出し
greeting('World')
---
Hello, World
  • *をつけると可変長の引数を指定することができ、値はタプルになる
    • listの場合も*をつけるとlistの値をタプルで指定することができる
      • *をつけない場合はlistが入ったタプルを指定することになる
      • *をつけないdictionaryの場合はdictionaryが入ったタプルを指定することになる
      • *をつけたdictionaryの場合はdictionary.keysのタプルを指定することになる
#可変長の引数を受け取り、それらを表示する関数 greeting
def greeting(*args):
  print(args)
#可変長の引数を受け取る関数 greeting に複数の引数を渡して呼び出し
greeting('Hello','Bonjour','Guten Tag')
#listの指定
greeting_list = ['Hello','Bonjour','Guten Tag']
greeting(*greeting_list)
#listを直接指定した場合はlistのタプルが出力される
greeting(greeting_list)
#dictionaryの指定
greeting_dict = {'en': 'Hello', 'fr': 'Bonjour', 'de': 'Guten Tag'}
greeting(*greeting_dict)
#値のタプルを指定したい場合はvaleus関数を指定
greeting(*greeting_dict.values())
# dictionaryを直接指定した場合はdictionaryのタプルが出力される
greeting(greeting_dict)
---
('Hello', 'Bonjour', 'Guten Tag')
('Hello', 'Bonjour', 'Guten Tag')
(['Hello', 'Bonjour', 'Guten Tag'],)
('en', 'fr', 'de')
('Hello', 'Bonjour', 'Guten Tag')
({'en': 'Hello', 'fr': 'Bonjour', 'de': 'Guten Tag'},)
  • **とするとタプルではなくdictionaryになる
    • dictionaryも指定できるが値は同じ
      • dictionaryで**をつけない場合はエラー
      • listを指定してもエラー
#可変長のキーワード引数を受け取り、それらを表示する関数 greeting
def greeting(**kwargs):
  print(kwargs)
#可変長のキーワード引数を受け取る関数 greeting に複数の引数を渡して呼び出し
greeting(en='Hello', fr='Bonjour', de='Guten Tag')
#辞書型オブジェクト greeting_dict を関数 greeting に渡して呼び出し
greeting_dict = {'en': 'Hello', 'fr': 'Bonjour', 'de': 'Guten Tag'}
greeting(**greeting_dict)
greeting(greeting_dict)
---
{'en': 'Hello', 'fr': 'Bonjour', 'de': 'Guten Tag'}
{'en': 'Hello', 'fr': 'Bonjour', 'de': 'Guten Tag'}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-fc1f91476705> in <cell line: 9>()
      7 greeting_dict = {'en': 'Hello', 'fr': 'Bonjour', 'de': 'Guten Tag'}
      8 greeting(**greeting_dict)
----> 9 greeting(greeting_dict)

TypeError: greeting() takes 0 positional arguments but 1 was given
  • 位置引数、初期値を持つ引数、可変長引数、辞書型の可変長引数は、同時に指定できるがdef 関数名 (位置引数, 初期値を持つ引数, 可変長引数, 辞書型の可変長引数)の順番で指定しないといけない
  • 変数名と同名の関数名もつけれる
    • そんなことするとコードが見にくいのでやるべきではない

ファイル入出力の基本

  • ファイルオープン、読み込み、クローズ等一般的なものがある
    • f = open('sample.txt', 'r')でファイルオープン
      • r(読み取り),w(書き込み),a(追記)を指定
    • f.read()でファイル全体を読み込む
      • 終端まで読むので2回実行すると2回目は空文字が返ってくる
    • f.readline()で1行ずつ読み込む
    • f.close()でファイルクローズ
    • with ファイルオブジェクト as 変数:とすると処理が完了したら自動クローズを行うので普段はこちらを使うべき
    • 書き込みはprint関数のfile引数を指定して書く
      • print関数は末尾に自動的に改行が入る
        • 改行を入れないようにするにはend引数を空で指定する
      • 複数の文字を渡すとデフォルトで空白文字で区切られる
        • sep引数を指定すると区切り文字を指定できる
    • print関数以外にwriteメソッドもある
      • 例のようにファイルをコピーする時などに便利
with open('print-test.txt', 'w') as f:
  print('hello\nworld', file=f)
  print('--', file=f)
with open('print-test.txt', 'a') as f:
  print('hello', 'world\n', end='', file=f) # 改行文字を加えない(文字列で改行を指定している)
  print('--', file=f)
with open('print-test.txt', 'a') as f:
  print('hello', 'world', sep=', ', file=f) # 'hello, world' が印字される
  print('--', file=f)
with open('print-test.txt') as src, open('print-test.txt.bak', 'w') as dst:
  dst.write(src.read())

これを実行するとprint-test.txtprint-test.txt.backが生成されて中身は2つとも以下のようになっている.

hello
world
--
hello world
--
hello, world
--

  • ファイルの読み書きには文字コード指定が必要
    • 例えばmacでShift-JISのファイルを開くとエラーになる(macはUTF-8)
    • encoding引数を指定すればよい
### これはエラーになる(shift_jis.txtがShift-JISで書かれたテキストの場合)
with open('shift_jis.txt', 'r') as f:
  print(f.read())
# encodingを指定することで読み書きができる
with open('shift_jis.txt', 'r', encoding='shift_jis') as f:
  print(f.read())
# 文字コードを指定してファイルに書き込む場合
with open('text.txt', 'w', encoding='utf-8') as f:
  f.write(' かきくけこ')
with open('text.txt', 'r', encoding='utf-8') as f:
  print(f.read())

text.txtには かきくけこと書き込まれている(writeなので改行はない)

イテラブルとイテレータ

  • ファイルオブジェクトはfor inで指定でき、1行ずつ処理できる(readlineと同じ)
lines = []
with open('print-test.txt', 'r') as f:
  for line in f:
    lines.append(line)
lines
---
['hello\n',
 'world\n',
 '--\n',
 'hello world\n',
 '--\n',
 'hello, world\n',
 '--\n']
  • iter関数でイテレーターが作成でき、next関数で1つずつ取得できる
    • 当然、値がない場合はエラー
it = iter([0,1,2])
print(next(it))
print(next(it))
print(next(it))
print(next(it))
0
1
2
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-9-61affd3ac96e> in <cell line: 5>()
      3 print(next(it))
      4 print(next(it))
----> 5 print(next(it))

StopIteration: 
  • エラーのcatchも可能でtry-catchではなくtry-except文となる
try:
  it = iter([0,1,2])
  print(next(it))
  print(next(it))
  print(next(it))
  print(next(it))
except StopIteration:
  print("except")
  pass
---
0
1
2
except
  • ファイルオブジェクトはイテレータになる
    • for inで1行ずつ処理できるのはイテレータだから?
f = open('print-test.txt', 'r')
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
f.close()
---
hello

world

--

hello world

--

hello, world

--

---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-20-5ab6dd666991> in <cell line: 9>()
      7 print(next(f))
      8 print(next(f))
----> 9 print(next(f))

StopIteration: 
  • next(f)f.readline()はほぼ同じだが終端の場合にStopIterationを発生させるのと空文字を返す違いがある
f = open('print-test.txt', 'r')
print(f.readline())
print(f.readline())
print(f.readline())
print(f.readline())
print(f.readline())
print(f.readline())
print(f.readline())
print(f.readline())
f.close()
---
hello

world

--

hello world

--

hello, world

--


  • イテラブルはイテレータではない
    • つまりイテラブルなリスト・タプル・文字列・辞書等はfor inで何回も実行しても同じ値を返すが、イテレータは1回しか返さない
      • 他の言語も基本同じじゃない?
# イテラブルなListの場合
xs = [0,1,2]
for x in xs:
  print(x)
print('--')
for x in xs:
  print(x)
print('--')
# イテレータの場合
it = iter([0,1,2])
for x in it:
  print(x)
print('--')
for x in it:
  print(x)  # 実行されない
---
0
1
2
--
0
1
2
--
0
1
2
--
  • リストのindexと値を返すenumerate関数
    • enumerate関数を利用するとリストのindexも同時に取得できる(タプル)
it = enumerate([10,20,30])
print(next(it))
print('--')
for x in it:
  print(x)
print('--')
for i, c in enumerate('ACDB'):
  print(i, ' 番目の文字 =', c)
---
(0, 10)
--
(1, 20)
(2, 30)
--
0  番目の文字 = A
1  番目の文字 = C
2  番目の文字 = D
3  番目の文字 = B
  • ファイルオブジェクトもenumerateに与えることができる
with open('print-test.txt', 'r') as f:
  for i, s in enumerate(f):
    print(i, '行目')
    print(s)
---
0 行目
hello

1 行目
world

2 行目
--

3 行目
hello world

4 行目
--

5 行目
hello, world

6 行目
--

ディレクトリと木構造

  • 特にメモすることなし

モジュールの使い方

  • 例えば平方根を計算するとき、import mathとすればmath.sqrt(2)とすればよい
  • fromをつけてfrom math import sqrtとすればsqrt(2)だけでいける(mathが不要)
  • mathの全てを利用したい場合はfrom math import *でよい
    • ただし、変数がモジュール定義関数と同名だと上書きされるので注意
      • そもそもそういうコードは書くべきではないが
pi = 'パイ' # pi という変数に文字列「パイ」を代入する
print(pi)
from math import *
print(pi) # math モジュールの pi の値で上書きされる(衝突)
---
パイ
3.141592653589793
  • as をつけると略称で使うことができる
    • モジュール名でも関数名でも利用可能
import numpy
print(numpy.ones((3, 5))) # 3 × 5 の行列を表示
import numpy as np
print(np.ones((3, 5))) # np という短い名称で同じ関数を利用する
import math
print(math.factorial(5)) # 階乗を求める関数 factorial # 5 の階乗
from math import factorial as fact # fact という名前で math.factorial を使用したい
print(fact(5))
---
[[1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]]
[[1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]]
120
120

モジュールの作り方

  • 特にメモすることなし

NumPy ライブラリ

  • NumPyは多次元配列を効率的に扱うライブラリで、標準ライブラリではないが、科学技術計算や機械学習など、ベクトルや行列の演算が多用される分野では、事実上の標準ライブラリ
  • numpy.array()関数で配列を作成できる
    • 要素はリストでもタプルでも良い
    • 配列はリストと似ているが違うものである
    • printで出力すると,ではなく空白で区切られる
import numpy as np

a = np.array([1,2,3]) # リストから配列作成
print(a)
b = np.array((1,2,3)) # タプルからの配列作成
print(b)
print([1,2,3])
---
[1 2 3]
[1 2 3]
[1, 2, 3]
  • そもそもlistとarrayとNumPy配列は違う
    • listの要素の型は何でもいいがarrayは数値型を要素とする。NumPy配列の要素はいくつかあるが基本は4つ
      • numpy.int32 整数(32-bit)を表す型
      • numpy.float64 実数(64-bit)を表す型
      • numpy.complex128 複素数(64-bit 実数の組)を表す型
      • numpy.bool_ 真理値を表す型
import array
import numpy as np

print(type(np.array([1,2,3])))
print(type(array.array('i', [1, 1, 2, 3, 5, 8])))
print(type([1,2,3]))
print(np.array([-1,0,1], dtype=np.int32)) 
print(np.array([-1,0,1], dtype=np.float64)) 
print(np.array([-1,0,1], dtype=np.complex128)) 
print(np.array([-1,0,1], dtype=np.bool_)) # 数値から真理値への変換では、0がFalseで、0以外がTrue 
---
<class 'numpy.ndarray'>
<class 'array.array'>
<class 'list'>
[-1  0  1]
[-1.  0.  1.]
[-1.+0.j  0.+0.j  1.+0.j]
[ True False  True]
  • numpy.array()に入れ子のリストやタプルを入れると多次元配列になる。
    • 行列のように各業の長さが等しくないとエラーになる
import numpy as np
print(np.array([[1,2],[3,4]])) # 2 次元配列の構築
print(np.array([[[1,2],[3,4]],[[5,6],[7,8]]])) # 3 次元配列の構築
print(np.array([[1,2],[3]])) # 行の長さが異なる場合
---
[[1 2]
 [3 4]]
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
[list([1, 2]) list([3])]
<ipython-input-10-e188171af870>:5: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  print(np.array([[1,2],[3]])) # 行の長さが異なる場合
  • 多次元配列はreshape()メソッドで作成することができる
  • ravel()メソッドで1次元配列に戻せる
    • ただし、reshape()やravel()を適用する前後の配列はデータを共有している
import numpy as np
a1 = np.array([0, 1, 2, 3, 4, 5]) # 1 次元配列
a2 = a1.reshape(2,3) # 2 × 3 の 2 次元配列
print(a2)
a1[1] = 6
print(a1)
print(a2)
a3 = a1.ravel()
print(a3)
a1[1] = 7
print(a3)
---
[[0 1 2]
 [3 4 5]]
[0 6 2 3 4 5]
[[0 6 2]
 [3 4 5]]
[0 6 2 3 4 5]
[0 7 2 3 4 5]
  • 配列はオブジェクトなのでプロパティが色々と存在する。
    • 代表的なものは次の通り
      • a.dtype 配列 a の要素型
      • a.shape 配列 a の形(各次元の長さのタプル)
      • a.ndim 配列 a の次元数(len(a.shape) と等しい)
      • a.size 配列 a の要素数(a.shape の総乗と等しい)
      • a.flat 配列 a の 1 次元表現(a.ravel() と等しい)
      • a.T 配列 a を転置した配列(a と要素を共有)

P159まで書いたが実作業にはいるために終了

Discussion