Pickle ,_thread, 「バイナリ操作」、
「ファイル操作」を紹介します。
また、「パッケージ管理」なども紹介しています。
モジュール検索パスのリスト
import sys
import os
# 親ディレクトリ絶対パスをモジュール検索パスに追加
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import sys
sys.path.append( '..')# 親ディレクトリ相対パスをモジュール検索パスに追加
from collections import deque
d=deque( ["AA","B","CCC"] )
d.append("DD")
print(d) # 表示内容『deque(['AA', 'B', 'CCC', 'DD'])』
t=d.popleft()
print(t) # 表示内容『AA』
print(d) # 表示内容『deque(['B', 'CCC', 'DD'])』
d.popleft()
print(list(d)) # 表示内容『['CCC', 'DD']』
d=deque(maxlen=3)
print(d) # 表示内容『deque([], maxlen=3)』
d.append(1)
print(d) # 表示内容『deque([1], maxlen=3)』
d.append(2)
print(d) # 表示内容『deque([1, 2], maxlen=3)』
d.append(3)
print(d) # 表示内容『deque([1, 2, 3], maxlen=3)』
d.append(4)
print(d) # 表示内容『deque([2, 3, 4], maxlen=3)』
d.append(5)
print(d) # 表示内容『deque([3, 4, 5], maxlen=3)』
prog = re.compile(pattern) result = prog.match(string)上記は、以下と同等です
result = re.match(pattern, string)一つのプログラムで何回も同じ正規表現を使う場合には、 re.compile() を使ってその結果の正規表現オブジェクトを再利用した方がより効率的です。
import re
ss ="AAAA\n123\nBB\nC\n9870\nDDD"
prog = re.compile('[0-9]+')
for s in ss.splitlines():
result = prog.match(s)
#print(result)
if result: continue
print(s)
import re #正規表現のモジュール
cookie="AA=aa,SESSID=12345.67,BB=12"
m=re.match('.*(SESSID=)([^,]*)', cookie) # 失敗の正規表現:'.*(SESSID=)(.*),' や'.*(SESSID=)(.*)$'
if m and m.lastindex >= 2 :
print(m.group(0)) #表示結果:「AA=aa,SESSID=12345.67」マッチした箇所全体(m.group()と等価?)
print(m.group(1)) #表示結果:「SESSID=」1番目のグループ
print(m.group(2)) #表示結果:「12345.67」2番目のグループ
print(m.groups()) #表示結果:「('SESSID=', '12345.67')」グループ全体をタプルで
cookie="AA=aa,SESSID=12345.67"
m=re.match('.*(SESSID=)([^,]*)', cookie)
if m and m.lastindex >= 2 :
print(m.group(2)) #表示結果:「12345.67」2番目のグループ
import hashlib
mail="manabu@hotmail.com"
s=hashlib.md5(mail.encode('utf-8')).hexdigest()
# 上記の引数は byte列である必要があるので、エンコードしている。
print(s) #「2abf4e1a1714ab446713137abc84fc85」
s=hashlib.md5(b'').hexdigest() # 空のバイト列
print(s) #「d41d8cd98f00b204e9800998ecf8427e」
import os
path = './train'
files = os.listdir('./train') # これで'./train'で示す相対パスで示すディレクトリ内のファイル、ディレクトリ内の名前を、リストで得られます。
files.sort() # リスト内を昇順で並び替えます。引数で、reverse=True を指定すると逆順
for file in files:
if(os.path.isdir(path + '/' + file)):
print("ファイル:", file)
elif(os.path.isfile(path + '/' + file)):
print("ディレクトリ:", file)
elif(os.path.islink(path + '/' +file)):
print("リンク:", file)
以下で、絶対パスや、そのディレクトリを表示している。(存在していなくても可能)
import sys
import os
path=os.path.abspath(__file__) # 自身のファイルの絶対パス取得
print(type(path), path )
dirname=os.path.dirname(path) # pathが存在するディレクトリのパス取得
print(type(dirname), dirname )
print( os.path.dirname("home/tarou/ai") )# 「home/tarou」を表示(実は存在しない)
path=os.path.abspath("c:/tarou/test.txt") # 存在しないパスを指定しているが可能
print(path )#「c:\tarou\test.txt」を表示
上記の、c:/tarou/test.txtのパスで パス区切り文字が\に変わっているのは
windosシステムで実行した場合です。(環境で変化します。)
import os
if os.path.isdir("img/") == False:
os.mkdir("img/") # (既に存在する場合はエラー)
abspath=os.path.abspath("img/") # ←この表現だけでは作れているか分からない。(存在していなくても可能)
print(abspath, os.path.isdir(abspath)) # 作れているか確認
import os
if os.path.isfile("img0/77.png") == False:
print("無い")
print( os.path.splitext( "img0/77.png" ) ) # ('img0/77', '.png') のタプルでファイル拡張子の情報が得られる
#ファイルがあれば削除
if os.path.isfile("src.png") : os.remove("src.png")
#ファイルが在れば名前変更
if os.path.isfile("tmp.png") : os.rename("tmp.png","src.png")
なお、近年は「os.path.abspath()」でなく、「pathlib.resolve()」が使われます。 参考
from pathlib import Path
p=Path(".")
print(p.resolve())
dirs=[x.name for x in p.iterdir() if x.is_dir()]
files=[x.name for x in p.iterdir() if x.is_file()]
print( dirs )
print( files )
ファイルパスからファイル名を取得する。
import os filepath = './dir/subdir/filename.ext' filename = os.path.basename(filepath) print( filename ) # 「filename.ext」が表示される。
"scr.png"が在れば、削除する
import os
if os.path.isfile("scr.png") : os.remove("scr.png")
"tmp.png"が在れば、名前を"scr.png"に変更する
import os
if os.path.isfile("tmp.png") : os.rename("tmp.png","scr.png")
os.renameメソッド以外に、os.replaceメソッドでも同様の動作ができます。
import shutil
shutil.copyfile("0.gif", "1.gif")
それ以外に、shutil.copy、shutil.copy2 のコピーメソッドがあります。
import os
import pathlib
import shutil
def copy_files( folder_src, folder_dst, prefix="" ):
''' folder_src内のファイル群をfolder_dst内にコピーする。
(コピーの際、ファイル名にprefixの接頭辞を付加する)'''
if not os.path.isdir( folder_src ): raise Exception(f"{folder_src}フォルダが存在しません")
if not os.path.isdir( folder_dst ): raise Exception(f"{folder_dst}フォルダが存在しません")
files_src=[ it.name for it in pathlib.Path(folder_src).iterdir() if it.is_file() ]
files_dst=[ it.name for it in pathlib.Path(folder_dst).iterdir() if it.is_file() ]
for cpfile in files_src:
srcfilepath=folder_src + "/" + cpfile # コピー元
dstfilepath=folder_dst + "/" + prefix + cpfile # コピー先
print( srcfilepath, dstfilepath) # コピー元と、コピー先の表示
if prefix + cpfile in files_dst:
print(f"{dstfilepath}が既に存在しているのでコピーしない")
continue
shutil.copy(srcfilepath, dstfilepath) # コピー
folder_src=input("コピー元フォルダパス>")
folder_dst=input("コピー先フォルダフォルダパス>")
copy_files(folder_src, folder_dst,prefix="COPY_") # ファイル群を第2引数フォルダに複製
import os
def filelist(path):
if path == "": path="."
try:
for f_name in os.listdir(path) :
file_info = os.stat(f_name)
file_size = file_info[6]
d_inf = 'dir' if (file_info[0] & 0x4000 ) else ' ' # ディレクトリ判定
print(f"{d_inf} {file_size:7} {f_name}")
except Exception as e:
print("Error :" , e)
pass
filelist(".")
この方法であれば、MicroPython、Pythonの両方で使えるようです。
import datetime
now = datetime.datetime.now() # 今日の日時取得
print(now) # 実行例:2017-09-17 00:26:44.404322
print( now.strftime("%Y/%m/%d %H:%M:%S") )# 実行例:2017/09/17 00:26:44
print( now.strftime("%Y%m%d%H%M%S") ) # 実行例:20170917002644
import time print( time.time() )# 実行例エポック時間:1635436928.5129068
import json
obj={"A":[[1,2,3],(4,5)], "B":['A','B','C'] }
s=json.dumps(obj)
print(s)
obj2=json.loads(s)
print(obj2)
dumpメソッドで、objをJSON形式のファイルやソケットにシリアル化します
import json
obj={"A":[[1,2,3],(4,5)], "B":['A','B','あいう'] }
with open('test.json', 'w') as f:
json.dump(obj, f, indent=2, ensure_ascii=False)
with open('test.json', encoding='unicode-escape') as f:
obj2=f.read()
print(obj2)
import pickle
a = [1,[2,3,4],[5,6] ]
data={ "W1" : a}
data["W2"]=["AB","CD"]
print(data) # 「{'W1': [1, [2, 3, 4], [5, 6]], 'W2': ['AB', 'CD']}」を表示
with open('test.pkl', mode='wb') as fw:
pickle.dump(data, fw) # 直列化 (Serialize) して保存
上記で保存したファイルからオブジェクトを復元する例を示します。
import pickle
with open('test.pkl', mode='rb') as fr:
data = pickle.load( fr ) # オブジェクトを復元する
print(data) # 「{'W1': [1, [2, 3, 4], [5, 6]], 'W2': ['AB', 'CD']}」を表示
from collections import defaultdict
sessDic = defaultdict(str)
import dill
sessDic['opraterMsg']="こんばんは" # sessDicの辞書に保存
sessDic['aiMsg']="おはよう"
#任意オブジェクト(sessDic)を保存
with open("testfile.bin", 'wb') as f:
dill.dump(sessDic, f)
from collections import defaultdict
sessDic = defaultdict(str)
import dill
# dill のファイルから、変数に復元
with open("testfile.bin", 'rb') as f:
sessDic = dill.load(f)
print(sessDic['opraterMsg']) # [こんばんは]の表示
print(sessDic['a']) # [おはよう]の表示
import sys print(type(sys.argv)) print(sys.argv)例えば、上記のコードにおいてpython test.py --model_path models --save Falseで実行させるとします。結果は次のようになります。
<class 'list'> ['test.py', '--model_path', 'models', '--save', 'False']さて、「--model_path」で指定した値が「models」で、「--save」で指定した値が「False」というように使いたいとします。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-m", "--model_path")
parser.add_argument("-s", "--save")
args = parser.parse_args()
print( type(args) )
print( args )
print( "args.model_path:", args.model_path )# 引数の値が[model_path]の名前で取得
上記のコードにおいてpython test.py --save False --model_path models で実行させるとします。結果は次のようになります。
<class 'argparse.Namespace'>
Namespace(model_path='models', save='False')
args.model_path: models
$ python test.py --help usage: test.py [-h] [-m MODEL_PATH] [-s SAVE] optional arguments: -h, --help show this help message and exit -m MODEL_PATH, --model_path MODEL_PATH -s SAVE, --save SAVE $なお、単に指定しないで「python test.py」と実行すると、次のようになります。
$ python test.py <class 'argparse.Namespace'> Namespace(model_path=None, save=None) args.model_path: None $また、add_argumentで指定しない引数名を指定すると、次のようなエラーがでます。
$ python test.py -value 123 usage: test.py [-h] [-m MODEL_PATH] [-s SAVE] test.py: error: unrecognized arguments: -value 123 $
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-m", "--model_path", dest="mpath")
parser.add_argument("-s", "--save")
args = parser.parse_args()
print( args )
|
$ python test.py -s False -m models Namespace(mpath='models', save='False') $ |
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-m", "--model_path", default="subdir")
parser.add_argument("-s", "--save" ,default=True)
args = parser.parse_args()
print( args )
|
$ python test.py Namespace(model_path='subdir', save=True) $ |
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--value", default=0.0, type=float)
args = parser.parse_args()
print( args )
|
$ python test.py --value 123 Namespace(value=123.0) $ |
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--flag", action='store_true')
parser.add_argument("-c", "--check", action='store_false')
args = parser.parse_args()
print( args )
|
$ python test.py Namespace(check=True, flag=False) $ python test.py -f Namespace(check=True, flag=True) $ python test.py -c Namespace(check=False, flag=False) $ |
import urllib.request
IRIS_TRAINING = 'iris_training.csv'
IRIS_TRAINING_URL = 'http://download.tensorflow.org/data/iris_training.csv'
if os.path.isfile( IRIS_TRAINING ) == False:
d = urllib.request.urlopen( IRIS_TRAINING_URL ).read();
print(d)
with open( IRIS_TRAINING ,'wb' ) as f:
f.write(d)
#
import sys
import time
import _thread # Python3では「_thread」を使う. (MicroPythonでも動作可能)
key_code = 0 #キーが押されたらキーデータがセット
def input_key(): # スレッドで実行予定のキー入力関数
print ("スタート")
c = sys.stdin.read(1) # 1文字入力
global key_code
key_code = c
# 新しいスレッドを開始して、input_keyを実行させ、そのIDを返します。
thread_id = _thread.start_new_thread(input_key, ())
count = 0
while key_code == 0:
count += 1
time.sleep(1)
print( count, "key:", key_code)
import threading, time
def sub2(d, t):
time.sleep(t)
print(d)
def thread_print(np_data, t):
thread_data= threading.Thread(target=sub2, args=( np_data ,t,))
thread_data.start() # スタート
return thread_data
thread_print(123,5) # 5秒後に表示
thread_print("ABC",2) # 2秒後に表示
a=[1,2,3] bs=bytes(a) print(bs) # 「b'\x01\x02\x03'」を表示 bs[0]+=3 # 「TypeError: 'bytes' object does not support item assignment」の実行エラー ba=bytearray(a) print(bs) # 「bytearray(b'\x01\x02\x03')」を表示 ba[0]+=3 # 可能 bs=bytes(ba) # 変換 print(bs) # 「b'\x04\x02\x03'」を表示バイナリ列から、2byte整数群への変換例
def array_16_from_binary(bdata, bigFlag=True,signFlagh=True): # バイナリから配列へ変換
a = []
for i in range(0, len(bdata), 2):
v2 = bdata[i:i+2]
print(v2)
if bigFlag:
d = (v2[0] << 8) + v2[1] # 2バイト、ビッグエンディアンで変換
else:
d = (v2[1] << 8) + v2[0] # 2バイト、リトルエンディアンで変換
if d >= 32768 :
a.append( - (65536 - d) )
else:
a.append( d )
return a
bdata = bytes(range(0,6)) + b"\xff\xfd\xff\xfe\xff\xff" #テスト用バイナリ生成 bdata # 出力: b'\x00\x01\x02\x03\x04\x05\xff\xfd\xff\xfe\xff\xff' b = array_16_from_binary(bdata) # ビックエンディアンで、2byteごとに変換 b # 出力:[1, 515, 1029, -3, -2, -1] b = array_16_from_binary(bdata, bigFlag=False) # リトルエンディアンで、2byteごとに変換 b # 出力:[256, 770, 1284, -513, -257, -1]
import numpy as np b = np.frombuffer(bdata, dtype="int16").tolist() # 上記と同じ結果が得られるnumpyのメソッド b # 出力:[256, 770, 1284, -513, -257, -1]
fr = open("t1321.txt", "br")
while True:
bin = fr.read(1) # 1byte 読み取り(引数のバイト数を読み取る)
if len(bin) != 1 : break
print( hex(bin[0]) ) # 先頭要素の int 値を 16 進文字列で表示
fr.close()
fr = open("t1321.txt", "br")
bin = fr.read() # 可能な限り読み取る
fr.close()
for i in range(len(bin)):
print( hex(bin[i]) ) # 各要素の int 値を 16 進文字列で表示
bs=b'\x80\x00\x00\x00' int.from_bytes(bs, 'little') # 128を表示 int.from_bytes(bs, 'big') # 2147483648を表示 int.from_bytes(bs, 'big',signed=True) # -2147483648を表示python3.2以降であれば、次のようなintからbytesへの変換メソッドがあります。
v=128 v.to_bytes(2, 'big') # 2バイトでビッグエンディアン で、b'\x00\x80'の表示 v.to_bytes(4, 'little') # 4バイトでリトルエンディアン で、b'\x80\x00\x00\x00'の表示
import struct
struct.pack("hh", 15,8) # b'\x0f\x00\x08\x00'の結果
struct.unpack("hh",b'\x0f\x00\x08\x00') # (15, 8)の結果
''' bitbyte.py
bit列をbyte列に変換、またはその逆変換用モジュール
bit列とは、(unsigned int , ビット数)の集合です。
'''
class BitByte:
def __init__(self, byteBuf=None):
self.byteBuf = byteBuf if byteBuf else bytearray(0)
self.bit32=0 # bit設定の作業用変数
self.bitCount=0 # 上記への記憶数 8を超えた毎に処理
self.bitSize=0 # データのビットサイズ
self.idx = 0 # 取り出す時の位置を記憶
#
def setData(self, data, bitSize): # bit列をbyte列に変換
'''bitSizeのビット数で、dataを記憶 (圧縮用)'''
bitmask = 2**bitSize-1
if data > bitmask : raise "Error"
self.bit32 |= data << self.bitCount
self.bitCount += bitSize
#print(f"{self.bit32:032b}")
while self.bitCount >= 8:
self.byteBuf.append(self.bit32 & 0x0ff)
self.bit32 >>= 8
self.bitCount-=8
#
def getBinary(self):
'''self内に記憶した全てのデータ(byteBufとbit32)のバイナリ列を返す '''
rtn = self.byteBuf.copy()
if self.bitCount > 0:
rtn.append(self.bit32 & 0x0ff)
return rtn
#
def getData(self,bitSize):
'''byteBufからbitSizeの情報を取り出して返す(解凍用) '''
bitmask = 2**bitSize-1
while self.bitCount < bitSize:
self.bit32 |= self.byteBuf[self.idx] << self.bitCount
self.bitCount += 8
self.idx += 1
val = self.bit32 & bitmask
self.bit32 >>= bitSize
self.bitCount -= bitSize
return val
#
def print(self):
''' 記憶内容を2進列で表示(getDataの実行前に使う) '''
a = self.getBinary()
for i,e in enumerate(a):
print(f"{int(a[i]):08b}", end=" ")
print(" 要素数:", len(a))
print("-------チョット確認--------------------")
d=BitByte() #圧縮用
d.setData(0b011, 3) #3ビットで記憶
d.setData(0b001, 3)
d.setData(0b100, 3)
a=d.getBinary()
print(a)
d.print() # 確認表示
d2=BitByte(a)#解凍用
print(d2.getData(3)) #取り出して3が表示
print(d2.getData(3)) #1が表示
print(d2.getData(3)) #4が表示
print("------詳細確認------------")
bits = [ v for v in range(2, 16)]
datas = [ 2**v-1 for v in bits]
ts=list(zip(datas, bits))
print(ts)
d=BitByte() #圧縮用
for data , bit in ts:
d.setData(data, bit)#dataをbitで記憶
#d.print() # 確認表示
print(d.getBinary())
d.print() # 確認表示
print("------記憶が終わって、以下で取り出しを行う")
d2=BitByte(d.getBinary()) #圧縮用
ts2=[]
for data , bit in ts:
v = d2.getData(bit)
ts2.append( (v, bit) )
print(f"bit:{bit:3} {v}" )
print(ts2)
print(f"ts==ts2の検証:{ts==ts2}")
pipはPythonのパッケージ管理システムです。2系、3系ともに最新のバージョンであれば標準で付属しています。 Pythonに付属しているpipのバージョン確認は、次の操作で行います。 pi@raspberrypi ~ $ python -m pip -V pip 9.0.1 from /home/pi/.pyenv/versions/3.5.2/lib/python3.5/site-packages (python 3.5) pi@raspberrypi ~ $ インストールされているパッケージを確認は、次のコマンドです。(「python -m pip list」でも可能) pi@raspberrypi ~ $ python -m pip freeze cycler==0.10.0 matplotlib==2.0.2 numpy==1.13.1 olefile==0.44 Pillow==4.2.1 Image用 psutil==5.2.2 pyparsing==2.2.0 python-dateutil==2.6.1 pytz==2017.2 six==1.10.0 tornado==4.5.1 pi@raspberrypi ~ $ インストールとアンインストール例 python -m pip install matplotlib python -m pip uninstall matplotlib インストールされているパッケージを無視して再インストール場合は、-Iオプション python -m pip install -I matplotlib ローカルや VCS からインストールしたい場合、-eオプション python -mpip install -e パスやURL pip アップグレード例 python -m pip install --upgrade pipPython 2とPython 3の間で大きくシステムが変わりました。