概要
- つらいけどpython3の勉強。最近流行ってるので習得しなければならない…
- 特徴
- 型がないので型ヒントを使う必要があり、型のテストも別途書く必要がある
- エディタ・統合開発環境・Python・envなどがグズグズに依存し合った時はじめて有用になる。
- 動的型にしますと言って結局型チェックするならはじめから静的型言語にすればいいし、それによる弊害で型テストなどマシマシで書かないといけないわけじゃん。本末転倒っぽくないですか。
- mypyで漸進的に型つけられる。なんなら型評価の段階で任意のスクリプトを実行できる。表現力が非常に高い。
下位ページ
目次
- まとめるべきこと
- 疑問
- 参考
- 環境構築
- 開発を始める時
- Jupyter Notebook
- 参考
- 文法
- Pythonの難しさ
- 関数にはオブジェクトのメンバ関数とグローバルの2つがアアル
- ドキュメンテーション
- バブルソート
- バージョン2と3のち外
- 代表的なデータ型の操作
- ファイル
- 正規表現
- numpy
- コーディングイディオム
- mapオブジェクト、filterオブジェクトなど
- 参照・ポインタ
- bitwise op.
- その他
- 注意
- 闇魔法
- 入出力
- 開発用
- Pythonでの高階関数
- クラス
- メモ
- Pandas
- Flisk
- Bookshelfの例
- Procfile
まとめるべきこと
collection系 https://docs.python.org/2/library/datatypes.html 調べたいもの:heap, bisect, setsとsetのちがい、ordered set, queueとstack, priority_queue, repr, Pythonのordered dict まんまOrderedDictという名前のcollectionがある http://azunobu.hatenablog.com/entry/2015/05/01/115413 お手軽構造体namedTuple http://sucrose.hatenablog.com/entry/2014/04/21/000909 dequeがある
pythonには亀グラフィクスという2Dグラフィクスが備わっている http://www.ic.daito.ac.jp/~mizutani/python/using_turtle.html
pythonの二分木 http://www.ic.daito.ac.jp/~mizutani/python/binary_tree.html
type hinting(タイポ) IFは書いた方がいいですね C++以外ですが、私はint,string,list,map,setの関数内変数についてはあまり書かないです PythonのIFにtype hitingするのもありかなって思います(書かない人多いですが) assert isinstance祭りしましょう
- デコレータ
- ラムダを与えて改造したラムダを返す。
- https://qiita.com/_rdtr/items/d3bc1a8d4b7eb375c368
- pythonの@はデコレータ
- 処理の前後に、処理を追加する
疑問
- 一般にPythonで変数を出力・ロードする方法ってどうすればいいの?
参考
- https://www.programiz.com/python-programming/numbers
- sympyなる数式演算ライブラリがイケてるらしいので後で調べる
環境構築
- 鬼門
sudo apt-get -y install python3-dev
python -V
python3 -V #バージョンを確認。3.5だとする。
sudo apt-get install python3.5-dev #ここのバージョンとして3.5を入れる
sudo apt-get install python3-setuptools
sudo easy_install3 pip
pip -V # pipの場所がpython3になっていることを確認
sudo pip install virtualenv
開発を始める時
- はじめて
virtualenv envname
pip3 install numpy
- 二回目以降
. envname/bin/activate
pip list # envname環境でのパッケージ
- 開発を終える時
deactivate
基本は使ってはならないがpip3について
- グローバルに入れるには、必ず使うバージョンまで指定しないといけない
sudo python3.5 -m pip install numpy
Jupyter Notebook
- 環境設定
pip3 install Jupyter
pip3 install jupyterlab
pip3 install pandas
pip3 install numpy
pip3 install SciPy
- jupyter-notebook の立ち上げ。これにより、カレントディレクトリにある .ipynb ファイルをインタラクティブに実行することができる。
jupyter-notebook
参考
文法
-
☆
- セミコロンなし,インデントが文法.
- 配列はmatlab式.[10, [20, 16], [32, u"太郎"], 18]など.スライス使える(a[1:2], a[:3], a[2:])が、スライス自体がリストにはならない.長さはlen(list),追記はlist.append(hoge).
- 数値配列の作成はrange(1, 5)など([1, 2, 3, 4])
- 文字列では、シングルとダブルクオートの区別がない
- 取得は配列と同じ
- pythonの文字列処理の素晴らしいまとめ
- ifに括弧なし.if, elif, elseはすべて行末に:
- forはmatlab式+行末に:.forのinに文字列は一文字ずつ取得.for, whileのあとにelseを入れることができる
- コメントは#comment, """comment"""
- 数字->文字はstr(num).文字→整数はint(str),文字→浮動はfloat(str),数値判定はstr.isdigit()
- 論理演算子はor, and, not.真偽はTrue, False
- 関数はdef function_name(arg1, ...):.行末に:が必要
- *でargs, **でパラメータを渡せる(参照)
- intも含め配列の関数渡しも、「すべて」参照渡し
- a={}でc++でいうmapになる
- pythonのdictは存在しないキーを出力しようとするとデフォルトエラーなので、そうじゃなくしたいならgetを使う。
- printf
- print aでprintf("%d\n",a);
- print a,でprintf("%d",a);
- for-else構文は、break「しなかったとき」に入るスペシャルステージ
- if 3>a>1<b<5: print(a, b)ができる!
-
☆☆
- 空オブジェクトはNone(Noneは予約語)
- 空白文字削除はstr.strip()
- Pythonは日本語がクソ
- 以下を一行目に入れる
# coding: UTF-8
- 可変長引数
>>> def func(*a):
... print a
...
>>> func("a","b","c")
('a', 'b', 'c')
- pythonのis operator
- ポインタの一致
- Immutableなら==と同じだが、リストとかmutableなものではポインタの一致を見るようになる
Pythonの難しさ
- 結局型を意識しなければいけないなら、型を全て省略する意味は一体どこにあるのだろう
- 理由: めんどいので(一方コードリーディングつらくない?)
- データオペレションのみに注力できるから、って思ったけど、少なくともいろい型やなんやらは考えてるので、見た目的に何もないだけで意識は、型から解放されてない
関数にはオブジェクトのメンバ関数とグローバルの2つがアアル
- pythonのsortやreverseなどは、配列のメンバ関数とグローバルの関数がある。sortedがグローバル
ドキュメンテーション
- pythonのクラスにはデフォルトで一番上の"""を__doc__で出力することができる
バブルソート
def bubblesort(a):
for i in range(len(a)-2):
for j in range(len(a)-1-i):
if a[j] < a[j+1]:
tmp = a[j]
a[j] = a[j+1]
a[j+1] = tmp
a=[2,4,5,1,2]
bubblesort(a)
for i in range(len(a)):
print a[i]
バージョン2と3のち外
- pythonのinput関数はpython 2だとeval(型推定)までしてしまうが、python 3ではstringを返すので変なことになりづらい
代表的なデータ型の操作
型の大まかな特徴
- pythonでは型が暗黙の了解となっている
- 型
- int, float
- iterativeな型:list, set(, str)。これらの間は自由に行き来できる(strはちょっと怪しい)
- strは静的!
- tuple
- tupleは静的!(1, 3, 4)[2]などのアクセスが可能。
- dict
- ndarray
- listしか突っ込めない
- map object
- このままでは使えないので、list, setに渡してやる必要がある(strはダメ)
- 変換
型の相互変換
| int | float | str | list | set | dict | ndarray | |
|---|---|---|---|---|---|---|---|
| int | = | float(n) | str(n) | [n] | {n} | {n: m} | np.array([n]) |
| float | int(x) | = | str(x) | [x] | {x} | {f: x} | np.array([x]) |
| str | int(s), 失敗でRE, int('0.1')はRE。ord(s)でもOKで、ordは1文字以外だとRE | float(s), 失敗でRE | = | list(s) | set(s) | x | np.array(list(s)) |
| list | a[i] | a[i] | str(a)は、listのデバッグ出力が文字列として得られる。a: [char]なら"".join(a)、a: [int]なら"".join(list(map(lambda x: chr(x+ord('0')), [0, 3]))) | = | set(a) | ts = [(1, 2), (3, 4), (5, 6)]; dict(ts)。同じようにdict(zip(a, b))などが可能(zipはzip objectでlistを返すわけではないが、list(zip(a,b))で同様になる)。キーだけ指定する場合は、marks = {}.fromkeys(['Math','English','Science'], 0) | np.array(a) |
| set | for x in s: print(x) | for x in s: print(x) | str(s)、setのデバッグ出力が文字列として得られる | list(s) | = | x | np.array(list(s)) |
| dict | d[x], xがなければRE | d[x], xがなければRE | str(d)、dictのデバッグ出力が文字列として得られる | list(d)はdのkeys list。dd.keys()は実はdict_keysという型!ペアで欲しいならlist(zip(d.keys(), d.values())) | set(d)はdのkeys set。d.keys()は実はdict_keysという型! | = | np.array(list(d)) |
| ndarray | v[i] | v[i] | str(a)でデバッグ出力らしきもの(違う)が出る | list(a)かa.tolist() | set(a) | x | = |
二次元配列
- 変な作り方をすると、参照になって代入が独立じゃなくなる。毎回リスト内包で作成すること!
型ごとに可能な操作
- str以外全部に対してビルトイン関数: all(), any(), enumerate(), len(), max(), min(), sorted(), sum()などが使える
- sequence(list, string)には、reversedが使える。
- sortedはstrを突っ込んでもリストが帰ってくる
| サイズ | 要素追加 | 要素削除 | 反復 | 積 | 和 | 差分 | 検索 | ソート | 逆順 | |
|---|---|---|---|---|---|---|---|---|---|---|
| list | len(a) | push_backがa.append(x), a.insert(i, x)はiの次にxを挿入する | push_backがa.pop()。a.pop(i)は#iを返して#iを消す。del a[i]で#iを消す。a.remove('a')でaを先頭1個削除(削除できないとRE) | [1] * 100 | なし | +, これは.extend(b)と同等 | なし | a.index('x'): xのfirst occurenceを取得 | a.sort() | a.reverse()が可能。reversed(a)でもまあ良い |
| set | len(s) | s.add(x) | a.discard(x)がエラー無し。remove(x)はxがないとRE。s.pop()はなんか一個削除して値を返す(順序がない、ハッシュなので)。 | なし | and | or。論理排他和は^。包含関係はa <= b | s-t | x in s, x not in s | setはハッシュなのでソートしてくれない!sorted(s) | なし |
| dict | len(d) | d[i] = x | d.pop(i)でkeyがiの要素削除して値を返す。d.popitem()で何か一つ削除して値を返す。 | なし | d = {x:d1[x] for x in d1 if x in d2} | なし | なし | d[i]はiがなければRE。d.get(i)はなければNoneを返す。 | sorted(d)だが、これはキーしかソートしてくれないのでsorted(list(zip(d.keys(), d.values()))) | なし |
| str | len(s) | s + t, O(len(s)+len(t)) | 不可能 | s*3 | なし | なし | なし | 'ab' in s | ''.join(sorted(s)) | ''.list(reversed(s)) |
list
- listには.countという出現回数を取得する関数がある
str
- **静的データ構造!!**途中で#iの変更をしたくなっても無理。変更にO(n)かかり、基本的に遅い。Javaみたいな感じ。
- 対策:動的文字列は、strではなくlistで管理する
- 'a'+1みたいなことをしたい場合は?めんどいが
chr(ord(s)+1)
- したがって+演算子は毎回新たなオブジェクトを生成するので、あまり行儀が良くない
s = s + "新たな文字列1"
s = s + "新たな文字列2"
. . .
とせずに、配列を使って、
L = []
L.append("新たな文字列1")
L.append("新たな文字列2")
. . .
s = ''.join(L)
とするのが定石イディオム
- split
- これは便利
- 複数文字delimiterもできる
>>> 'I have a pen'.split()
['I', 'have', 'a', 'pen']
>>> 'aabbababbabbbb'.split('a')
['', '', 'bb', 'b', 'bb', 'bbbb']
>>> 'aabbababbabbbb'.split('aa')
['', 'bbababbabbbb']
-
文字列にはupper, lowerという関数がある
-
小文字リスト
import string
string.ascii_lowercase
‘abcdefghijklmnopqrstuvwxyz’
その他のデータ構造
- Counter
- 便利
from collections import Counter
Counter([‘apple’,‘red’,‘apple’,‘red’,‘red’,‘pear’])
Counter({‘red’: 3, ‘apple’: 2, ‘pear’: 1})
ファイル
for line in open("test.txt", "r")
line.strip()
print line
正規表現
import re
a = re.search(r'^[a-z]', line)
numpy
Numpy Transposeに同値な Tというメンバ変数らしきものがあるhttps://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.T.html pythonできれいな2次元グラフを書く http://qiita.com/kenmatsu4/items/d282054ddedbd68fecb0 パラメータ分布を{coda}パッケージを使ってプロットするとこんな感じです。
ndarray
- スライスアクセス
- ファンシーアクセス
- 要素アクセス
import numpy as np
ndarr = np.array([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]])
indices = [1,1] # row,col
ndarr[tuple(indices)]
逆引き
- countしたい場合
np.count_nonzero(v==-1)
- npでmapしたい場合
np.vecorize(func)(v)
- 0配列を作る
np.zeros(n)。
- max, min
max(v), min(v)
- 条件を満たすインデックス列挙
np.where(a>1)
コーディングイディオム
not a
- C++のa.empty()はnot aで可能
隠れビルトイン関数
-
pow(x, y[, z])
- x^y%zの高速実装
- 競プロのために作られたとしか思えないがRSA暗号で使う
-
sorted(d.items(), reverse=True)
- 逆順ソートする。
-
all, any
- iterableの全てTrue、もしくはどれかがTrueでTrue
-
bin(int)
- 二進数表記する
-
ascii(obj), repr(obj)
- printで出力される文字列と同じものを返す
-
complex(re, [im])
- 複素数。文字列を突っ込むことができる。
-
divmod(a, b)
- 商と余りのtuple。divmod(10.2, 3)=(3.0, 1.1999999999999)
-
int(str, [base=10])
- a = int('1000', base=3)で81になる
-
普通のint型n
- 普通にC++と同じようなbit操作が可能。n & (1 << 4)
- n.bit_length()は二進数桁数。log2と同じ。
-
普通のfloat型x
- x.is_integer()は整数かを雑に判定する。if abs(x - int(x)) < 1e-6:とかしなくて良くなる
-
str
- countという部分文字列のカウントがある。 'abcabcbcbc'.count('bc') # 4
- findは、最初の出現位置を返す。なければ-1 'abcabcbcbc'.find('bc') # 1
- replaceは全出現の置換 'abcabcbcbc'.replace('bc', '')
- stripは前後の空白文字を消去する。
C++より実装速度が早いアルゴリズム
- 気軽にsplitとかを前提にしたアルゴリズムを組めるのはいい
- setの|や&
- reversed(range(10))はrange(10)[::-1]でもできる。
内包表記
- 内包表記には後置if条件を複数つけることができる。
- [x for x in range(100) if x % 2 if x % 3]
- if-elseもできる。前置になる
- [ i if i%2==0 else str(i) for i in range(10)]
- 速度的にも3倍程度早い
- gotoモジュールはデフォルトではなく、頑張ってインストールしなければならないので残念。多重ループ抜け出しは基本for-elseかフラグしか方法がなさそう。あとは関数化
一括比較・一括処理
- swap
a, b = b, a
- 一括等価チェック
- 複数のオブジェクトの比較はつなげて一度に行う
# long
# 最初の文字と最後の文字両方が一致する
a[1] == b[1] and a[-1] == b[-1]
# short
a[1] + a[-1] == b[1] + b[-1]
- リストで場合分け
- これはC++でもできそう
# long
t = a % 3
if t == 0:
a = a * 2
elif t == 1:
a = 0
elif t == 2:
a = t * 2
# short
a = [a * 2, 0, t * 2][a % 3]
- if-elseの代わりにand orを使うワンライナー
条件 and True時 or False時
- forのワンライナー。:は一行一個だが、それ以内のものはセミコロンでくっつけられる。
for x in[None]*10:print(a);a+=1
- forでループ変数は絶対に参照しないぞという気構え(range書くより短い)
for _ in [1]*10:
mapオブジェクト、filterオブジェクトなど
- ジェネレータと呼ばれるらしい
- リストなどの遅延評価
- 評価するには、for文なのでgenerateするか、明示的にlist(map_object)などとする([map_object]はだめ)
参照・ポインタ
概要
- pythonの変数は全て参照!
- 変数に新たなオブジェクトそのものが代入されるときには、これまでの参照先から変わって新たなオブジェクトが作られた場所を参照するようになる。
まず
-
とりあえずこれ動かしてなんかヤバイことを察して
-
1つめ
>>> a = [1,2,3]
>>> b=a
>>> b[0]=3
>>> a
[3, 2, 3]
>>> b
[3, 2, 3]
>>> b += [4]
>>> a
[3, 2, 3, 4]
>>> b
[3, 2, 3, 4]
- 2つめ
>>> L = [1,2,3,4]
>>> def func(ll):
... ll = [5,6,7,7]
...
>>> func(L)
>>> L
[1, 2, 3, 4]
- 3つめ
>>> def func(ll):
... ll[0] = 5
...
>>> func(L)
>>> L
[5, 2, 3, 4]
注意すべき挙動
-
listを関数に渡して、
- リスト全体を変えた場合は副作用がないが、
- リストの一部を変えると副作用が起きる
- 対策:func(a[:])とコピーを渡す。もしくは、関数内部始めに必ずdeep copyしてから使う。
-
二次元配列を[[0]*m]*nで実装するとダメ
- 超有名なのでググッて
- 対策:リスト内包表記を使う
-
クラスの初期値を[]にするとダメ
- http://amacbee.hatenablog.com/entry/2016/12/07/004510
- 対策:デフォルト引数やクラス初期値は、a=Noneをいれておいて、if a==None: a = []とする。
-
関数のデフォルトにMutableを入れるとダメ
pythonの変数と実体は独立
-
変数は全部ポインタ
- 変数はラベルでしかなく、実体と独立にふわふわ浮いている
-
代入
- 変数にオブジェクトを代入すると、
- 変数にオブジェクトの参照が代入される
- 変数に変数を代入すると、
- 変数に、変数が持つオブジェクトの参照が代入される
- 変数にオブジェクトを代入すると、
-
関数呼び出し
- 関数内部の変数に、入れた変数の参照が代入される
-
例:以下は、4行出力するうち、3番目のみ相違となる。
def func(x):
print(id(x))
x = 3
print(id(x))
a = 1
print(id(a))
func(a)
print(id(a))
- これはC++に例えると、こうなる(thx to hakuyume君)
なぜimmutableとmutableで説明がつくと思っているのか
- なんか皆immutableだからかーふーんと言っているが、なぜあの理解で理解できていると思っているのか理解できない
- listはおそらく、listオブジェクトの中にいっぱいintの参照が詰まっている
- list[0]を変更しようとした場合、listオブジェクトの0番目のintの参照を張り替える必要がある
- mutableというのは、おそらくこれが可能というだけであって、listだからという話ではないと思う
- 実際に、listそのものを完全に代入しなおした場合、listオブジェクトが変わるのでmutableだがidが変わる
- したがって、mutableオブジェクトの場合、mutableオブジェクトのメンバ変数を実行可能だというだけで、それが関数渡しのidの話とは直接関係ないのでは?と感じている
- list[0]を変更しようとした場合、listオブジェクトの0番目のintの参照を張り替える必要がある
pythonのポインタのようなもの
- idというものでポインタが取れる
a = 1
id(a)
リストのdeep copy
- a[:]とするとdeep copyができる
>>> a = [1,2,3]
>>> b = a[:] # b = list(a)とか、b = copy.copy(a)でも大丈夫
>>> a
[1, 2, 3]
>>> b
[3, 2, 3]
関数わたし
-
重要:list, dict, set, bytearrayは、自身を変更できるので、参照渡しであることを強く意識せねばならない
-
関数に渡された値を変更した際に元の値自体も変更できるどうかは,オブジェクトの型に依存
- 変更不可(Immutable)な型
- int, float, str, tuple, bytes, frozenset 等
- 変更可能(Mutable)な型
- list, dict, set, bytearray 等
- 変更不可(Immutable)な型
-
int型を参照わたししたいときは?
- int型に変更できる余地がないので無理です
bitwise op.
- bytearrayをつかう?
その他
-
sqrt(n)
- n**0.5ができる
-
数学変数
- pi, e, infなどは、math.pi, math.e, math.infなどでアクセスす
-
pythonのfor内部で添字をいじっても意味ないので注意!!!
- C++ではたまにfor内部でiを加速するが、pythonは毎回代入される。
-
2**100000くらいならまあ余裕で計算できる
注意
- {}はどっち?
- dictであり、setではない
- s = set()とする
闇魔法
- 無理やりapplicableっぽくするやつがある
入出力
- 改行なし
import sys
sys.stdout.write(str)
開発用
デバッグ
-
assert 条件式, ‘エラーメッセージ’
-
そもそもコンパイルレベルで発覚するミスをどうやって未然に検出するんだろう?
-
loggerという、デバッグレベルを設定できるパッケージがある
引数の扱い
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('processes', type=int)
parser.add_argument('--env', type=str, default='CartPole-v0')
parser.add_argument('--arch', type=str, default='FFSoftmax',
Pythonでの高階関数
- [[「なぜ関数プログラミングは重要か」という文章>http://qiita.com/kwatch/items/03fd035a955235681577#%E8%A8%88%E7%AE%97%E5%BC%8F%E5%A4%89%E6%8F%9B%E5%BC%8F%E3%82%92%E5%8F%97%E3%81%91%E5%8F%96%E3%82%8B%E9%AB%98%E9%9A%8E%E9%96%A2%E6%95%B0
]]
- ソフトウェアがどんどん複雑になるので、モジュール化が重要
- 関数型言語は、強力なモジュール化機能を提供している
- 特に「高階関数」と「遅延評価」が重要である
- 関数型言語の良さを関数型言語のコードで説明しているので、関数型言語を知らないユーザにはちっとも伝わらない
クラス
- Pythonのコンストラクタは__self__
- classでは全てのメンバ関数に第一引数selfを入れる必要
- メンバ変数も全てself.を付ける
- デフォルト変数定義ない。動的に決まる。コンストラクタで初期化する。
メモ
- バッチ系関数群
- Map, Reduce, Filter
- Cの共有ライブラリを使う
- 型指定して高速化
- そして更にNumpy+Cythonで爆足
- 多次元配列
- ヒートマップの書き方
Pandas
- https://openbook4.me/projects/183/sections/777
- https://qiita.com/hi34/items/43c366dea18b46faf49d
- チートシート
- SeriesとDataFrameの2つがある
- ベクトルや、行列の行と列に名前が付いている感じ
- 縦の名前がindex, 横の名前がcolumns
- API
- s = pd.Series([1,2,3], index=['a','b','c'])
- DF作成
- df = pd.DataFrame([1,4,7],[2,5,8],3,6,9, index = ['i1','i2','i3'], columns = list("abc"))
- foo = pd.DataFrame({'bar': [0, 1, 2],'baz': [3, 4, 5]}, index=['a', 'b', 'c'])のようにしてcolumnsを指定することもできる。
- 後でつけることもできる。df.column = ['a', 'x', 'c']とか、df.index = ['i1','i2','i3']とか
- dict<T, array
>を食わせても初期化する。
- 要素取得
- df.ix[1,2],'b','c'でDataFrameが、df.ix[:, 2]でSeriesが、df.ix[1,1]でスカラが帰ってくる。名前でも番号でもOK
- df['a']はdf.ix[:, 'a']であって、混乱する。。
- df[df>1]などで、条件を満たさないものをNaNにする感じ。df[df>1]=INFのようにできる。
- 追加
- foo['new_column'] = [6, 7, 8] # 横に追加
- foo.append(pd.DataFrame({'bar': [6, 7], 'baz': [8, 9}, index=['d', 'e'])) # 縦に追加
- pd.concat([df1, df2]) # 縦に追加
- df.append(df2, ignore_index=True) # 縦に追加
- df1.join(df2) # 横に追加
- 削除
- foo.drop('e') # 行を削除する
- foo.drop('bar', axis=1) # 列を削除する
- 変なindexing
- day_no
- df_sample.query("day_no == 'day1'|day_no == 'day2'")
- select_condition = "day1"; df_sample.query("day_no == @select_condition")
- df_sample.query("index == 11 ")
- df_sample.query("index in [11,12] ")
- 読み出し
- pd.read_csv('foo.csv', header=0)
- df.to_csv('bar.csv', index=False)
- データのチラ見
- df.head(), df.tail()
- 基本情報
- df.shape # 縦横の形
- 転置
- df.T
- numpy
- df.valuesでnumpy配列や行列になる
Flisk
- Flaskオブジェクトには、config.from_objectという関数があって、import configとしたconfigをそのまま突っ込める
- url_forの前にある.は同じblueprintに属することの明示
- blueprintは、アプリケーションを分離するための仕組み。
- url_for("func", xx=hoge)と書くと、routeの中ではなくて、pythonの関数名に相当する部分に飛ぶようになる。また、xx=hogeと書くと、
にそれが入ったかのようにURLが生成される。」「
Bookshelfの例
Bookshelfの例、異常に多くのツールを使っていて優しくない サービスとバージョンの設定方法については理解できた psqworkerという謎のCLIが存在して、これを設定するとpsq queueを返すpython関数のパスを指定して、そこに溜まっているタスクをひたすらやりつづけるという挙動をするらしい どれくらいのメッセージがpubsubでどこにやり取りされているのか?workerは何個立ち上がっているのか?などの情報がどこにあるのかわからない。 やっとなんとなくわかった。publisherがtopicにデータをpushすると、それのハードコピーがtopicと結びついているすべてのsubscriptionにpushされて、subscriberは適宜subscriptionをpopしていく感じ
bookshelfアプリでは、 psqworkerコマンド(in: pythonのqueueオブジェクトを返す関数への=main.books_queueとか。 out: void, 副作用あり) が勝手にdequeueするらしい。 enqueue(関数, [引数]*)みたいな感じでやる。
The app uses Honcho, a Python port of the Foreman process manager, to manage multiple processes. The processes are configured by using a procfile. procfileに書いたプロセスを管理するコマンド(ちなみに日本語の班長に相当するもので、hanchoではなくてhoncho)
Procfile
web1: python app.py 8081 web2: python app.py 8082 のようにして、同時に複数のアプリを異なるportにexposeするためのツール
pythonのwith構文は、定形初期化と終端処理を含むクラスの処理(「開始と終了に必ずしなければいけない一連の作業がある場合」に便利)。例えば、ファイルなどは開くときにopenして読み終わったときにcloseするのだが、close歯忘れたりするとめんどい。また、定形のものだったらコーダーが木にしなくてもちゃんと終了処理できるようになってくれという気持ちから作られた構文。
pythonのimportはcppのinclude guardのようなものがないので、circular importという問題が起きる。それを回避するためのパターンとして、参照だけimportするみたいなパターンがあるみたい。 例として、Flask アプリのメインファイル (例: app.py) から他のモジュール (例: db.py) をインポートするケースを考えます。 app.py 内では app = Flask(name) にて、Flask アプリを生成します。 db.py は、インポートされることを想定していますので、db.py 内では app を定義しません。ですが、 app.config['SQLALCHEMY_DATABASE_URI'] のように、app.py で生成する app の情報にアクセスするケースがあります。 そこで、app.py から app をインポートしてしまうと、app.py & db.py が双方で app を生成するループができてしまいます。(マニュアルでは circular import issues と言っています) それを回避するのが current_app です。
current_app は、app の擬似的なもので app のインポートせずに利用できます。なので、app.config['SQLALCHEMY_DATABASE_URI'] は、current_app.config['SQLALCHEMY_DATABASE_URI'] とすることで、app の双方のファイルによる生成ループを回避できます。
loggerは、以下のようにcurrent_appというクラスをflaskからimportしてきて、その中のloggingを使ったほうがlogging生で使うよりも行儀が良いらしい
current_app.logger.info(
"Uploaded file %s as %s.", file.filename, public_url)