[メモ]Pythonプログラミングパーフェクトマスター

· ·

基礎本読み : 「Python プログラミングパーフェクトマスター[Python3/Anaconda/PyQt5 対応第 3 版]」。

後半はダメだと分かっていつつも流し読みで最後まで読む事を重視。アプリ開発からディープラーニングまで幅広く網羅されているなぁという印象。

メモ 🔗

  • 可変長パラメータ、普段全然使ったこと無いなぁ
  • *args で可変長パラメータを受けて、 args で取り出せるのね
1
2
3
def sequence_sound(*args):
    for a in(args):
        print(a)
  • dict 型のパラメータもあまりつかってないかなぁ
  • キーワード引数を渡す。(key1 = value1, key2 = value2)的な
1
2
def attacks(**kwargs):
    print(kwargs)
  • def 関数名(パラメータ1, パラメータ2, *args, **kwargs) の並びで位置型、可変長型、辞書型の順でパラメータを設定できる
  • 高階関数 : 関数のパラメータの引数で別の関数を渡す
1
2
def run_something(func):
    func()
  • 関数内関数…全然使ったこと無い
1
2
3
4
def outer(a, b):
    def inner(c, d):
        return c + d
    return inner(a, b)
  • yield : ジェネレータ関数。return の代わりに使用して反復処理のたびに、最後に呼び出された時にシーケンスのどこを指していたのか覚えていて、次の値を返すもの。 range もジェネレータ関数。
  • yield は他の人が書いているソースコードとか見ていてちゃんと調べてなかった。
  • クラス変数 : インスタンス.__class__.クラス変数名 で呼び出すとクラスの中で参照先が一緒となり呼び出すたびに初期化されることがなくなる
  • ゲッター・セッターは言葉しか知らない…
  • 変数を隠蔽(カプセル化)すると、その変数へのアクセスは property 関数を通じてしかできなくなる
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class CapsuleCoarch:
    def __init__(self, max = 5, count = 0):
        self.__max = max
        self.__count = count

    def get_max(self):
        return self.__max

    def set_max(self, max):
        self.__max = max

    max = property(get_max, set_max)
  • class の他の関数または外部からは CapsuleCoarch.max と普通に書くと property 経由でのアクセスとなる
  • UI デザインはPyQTQT Designerを使う
  • QT Designer で作った GUI を XML で吐き出したら pyuic5 で python コードへ変換する。リソースファイルの .qrcpyrcc5 で python コード化
  • ファイルの読み込みまわりはいつもコピペしているような気がするから改めて
1
2
3
4
5
6
7
file = open('dictionary.txt', 'r', encoding = 'utf_8')
data =file.read()
file.close()

lines = data.split('\n')
for line in lines:
    print(line)
  • read() readline() readlines() あたりの使い分け
1
2
3
file = open('dictionary.txt', 'r', encoding = 'utf_8')
lines = file.readlines()
file.close()
  • with ステートメントでファイルを open した場合はいてレート可能なファイルオブジェクトとして返され、ファイル終端に達すると、ファイルオブジェクトが自動的に close される
  • 常に with ステートメントが必要なものかと思っていた
1
2
3
with open('dictionary.txt', 'r', encoding = 'utf-8') as f:
    for line in f:
        print(line)
  • readlines() で読み込んだ場合は改行も読み込まれる。改行を取り除く場合は rstrip() メソッドを実行すると良い
1
2
for line in lines:
    str = line.rstrip('\n')
  • 正規表現マッチングでは match() は文字列の戦闘に対してパターンマッチ、 search() はパターンがどこにあってもマッチする
  • 今回は TAB 区切りの文字列辞書で対話 bot を構築するが、対話パターンをそれぞれキーとリストという辞書形式で取得する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
"""
以下を実行すると...
{
    'pattern': []
    'phrases': []
}
となる
"""
patternDictionary = {}
for line in lines:
    ptn, prs = line.split('\t')
    patternDictionary.setdefault('pattern', []).append(ptn)
    patternDictionary.setdefault('phrases', []).append(prs)
  • 対話 bot で Emotion を追加する場合、機嫌値を-15~15 の範囲とし、機嫌値も含めたパターン辞書へ変更する。機嫌値は ## で区切って書き込む
1
5##かわいい|可愛い|カワイイ|きれい|綺麗|キレイ  %match%って言った?
  • 対話 bot の感情値操作。自然と機嫌値が 0 へ戻るように 0.5 ずつリカバリする
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Emotion:
    MOOD_MIN = -15
    MOOD_MAX = 15
    MOOD_RECOVERY = 0.5

    def __init__(self, pattern):
        self.pattern = pattern
        self.mood = 0

    def update(self, input):
        if self.mood < 0:
            self.mood += Emotion.MOOD_RECOVERY
        elif self.mood > 0:
            self.mood -= Emotion.MOOD_RECOVERY

        for ptn_item in self.pattern:
            if ptn_item.match(input):
                self.adjust_mood(ptn_item.modify)
                break

    def adjust_mood(self, val):
        self.mood += int(val)
        if self.mood > Emotion.MOOD_MAX:
            self.mood = Emotion.MOOD_MAX
        elif self.mood < Emotion.MOOD_MIN:
            self.mood = Emotion.MOOD_MIN
  • 辞書から機嫌値を取り出し辞書化
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class PatternItem:
    SEPARATOR = '((-?\d+)##)?(.*)$'

    def __ init__(self, pattern, phrases):
        self.initModifyAndPattern(pattern)
        self.initPhrases(phrases)

    def initModifyAndPattern(self, pattern):
        m = re.findall(PatternItem.SEPARATOR, pattern)
        self.modify = 0
        if m[0][1]:
            self.modify = int(m[0][1])
        self.pattern = m[0][2]

    def initPhrases(self, phrases):
        self.phrases = []
        dic = {}
        for phrase in phrases.split('|'):
            m = re.findall(PatternItem.SEPARATOR, phrase)
            dic['need'] = 0
            if m[0][1]:
                dic['need'] = int(m[0][1])
            dic['phrase'] = m[0][2]
            self.phrases.append(dic.copy())

    def match(self, str):
        return re.search(self.pattern, str)

    def choice(self, mood):
        choices = []
        for p in self.phrases:
            if(self.suitable(p['need'], mood)):
                choices.append(p['phrase'])
        if(len(choices) == 0):
            return None
        return random.choice(choices)

    def suitable(self, need, mood):
        if(need == 0):
            return True
        elif(need > 0):
            return (mood > need)
        else:
            return (mood < need)
  • findall() はカッコで囲んだ部分に対応する文字列が取り出せる。複数の場合はタプルリスト
1
re.findall('(a(bc))x(yz)', '123abcxyz') # [('abc', 'bc', 'yz')]
  • janome analyzer モジュール生成
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import re
import janome.tokenizer

def analyze(text):
    t = janome.tokenizer.Tokenizer()
    tokens = t.tokenize(text)
    result = []

    for token in tokens:
        result.append(
            [token.surface, # 形態素取得
            token.part_of_speech] # 品詞情報取得
        )
    return(result)
  • マルコフ連鎖 : ある状態が起こる確率が直前の状態から決まること
  • マルコフモデル : マルコフ連鎖によって状態が遷移することを表した確率モデル
  • requestsモジュールでの外部インターネットアクセス
  • OpenWeatherMap 例
1
2
3
4
5
6
7
import requests
import pprint

API_KEY = ''
URL = 'http://api.openweathermap.org/data/2.5/'
place = 'TOKYO'
data = requests.get(URL + 'weather?lang=ja&q=' + place + '&appid=' + API_KEY).json()
  • beautifulsoup4 例
1
2
3
4
5
6
7
import requests
from bs4 import BeautifulSoup

xml = requests.get('http://news.yahoo.co.jp/pickup/science/rss.xml')
soup = BeautifulSoup(xml.text, 'html.parser')
for news in soup.findAll('item'):
    print(news.title.string)
  • 文字識別の学習
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.optimizers import Adam

(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(60000, 784)
x_train = x_train/255
x_test = x_test/255

num_classes = 10
y_train = np.utils.to_categorical(y_train, num_classes)
y_test = np.utils.to_categorical(y_test, num_classes)

model = Sequential()

model.add(Dense(512, input_shape(784,), activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy'])

model.summary()

batch = 32
epochs = 10

history = model.fit(x_train, y_train, batch_size=batch, epochs=epochs, verbose=1, validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
comments powered by Disqus