pythonメニュー

Pythonの良く使うモジュールやクラス紹介

Pickle ,_thread, 「バイナリ操作」、 「ファイル操作」を紹介します。
また、「パッケージ管理」なども紹介しています。

モジュール検索パスのリスト

sys.path は Python の モジュール検索パスのリストで、インポート文が実行されるときに、Python はこのリストの順番に沿ってモジュールを探しにいきます。
import sys
import os
# 親ディレクトリ絶対パスをモジュール検索パスに追加
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import sys
sys.path.append( '..')# 親ディレクトリ相対パスをモジュール検索パスに追加

コレクション(collections.deque)

リストはキューとして使うこともできる。 しかし、リストの末尾に対するappend や pop は高速であるが、 先頭要素でのinsertやpopは低速である。 それで、キューの実装では、collections.deque
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)』

正規表現でマッチング

参考: https://docs.python.org/ja/3/library/re.html
「import re」 して使います。
以下では、patternの正規表現文字列で、stringの文字列に対するマッチ情報をresultに得ています。
prog = re.compile(pattern)
result = prog.match(string)
上記は、以下と同等です
result = re.match(pattern, string)
一つのプログラムで何回も同じ正規表現を使う場合には、 re.compile() を使ってその結果の正規表現オブジェクトを再利用した方がより効率的です。
具体例として、複数の行を記憶する文字列ss から数字だけの行を除いて表示する例で示します。
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)

マッチング文字列をgroupで取得

以下は、cookieの文字列から、'SESSID='直後の「12345.67」を、2番目のグループで得るコードを検証している例である。
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」

os モジュールのディレクトリ、ファイル操作

ディレクトリ内のファイル、ディレクトリ取得例を以下に示します。
「os.path.isfile」のように、ファイルであるかを調べる関数は、ファイル存在の有無に利用することも可能です。
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システムで実行した場合です。(環境で変化します。)
なお os.sepの表現で、パス内のフォルダやファイルを区切るセパレータが得られます。(\や/)
(パスとパスを区切る文字は、os.pathsepで得られます。(;や:))
カレントディレクトリに「img」フォルダが無ければ、「img」フォルダを生成して、絶対パスを確認するコードを示します。
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メソッドでも同様の動作ができます。
(なお、これはフォルダの名前変更にも使えますが、 変更後の名前と同じ名前のファイル名が存在する場合などで、挙動が違う。)
なお、ファイルのコピーでは、一般にshutil.copyfileを使います。その例を示します。
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引数フォルダに複製

MicroPythonでファイルサイズを取得する場合、os.path.getsize(file_path)の取得ができません。 次のようなコードで、「ディレクトリ、サイズ、ファイル名」をリストアップできます。
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の両方で使えるようです。

datetime モジュールの日時

日時の文字列取得例
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

jsonモジュール

dumpsメソッドで、objをJSON形式のstrにシリアル化します。
そのstrからオブジェクトに復元する場合は、loadsメソッドを使います。
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形式のファイルやソケットにシリアル化します
そのファイルから、オブジェクトに復元する場合は、loadメソッドを使います。
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)

オブジェクトのシリアライズ

pickle モジュール

(参照: https://docs.python.org/ja/3.6/library/pickle.html )
Python のオブジェクトを直列化 ・非直列化するための機能を提供している。
直列化 (Serialize) はオブジェクトをバイト列などの表現に変換すること。(Pickle 化 [Pickling] と呼ぶらしい。)
非直列化 (Deserialize) はその逆で、バイト列を元にオブジェクトを復元すること。(非Pickle 化 (Unpickling) と呼ぶらしい。)
以下に直列化 (Serialize) してファイルに保存する例を示します。
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']}」を表示

dillモジュール

pickle モジュールと同じような使い方ができるdillモジュールの例を示す。
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']) # [おはよう]の表示

argparse モジュール(コマンドライン引数を扱う)

単純にコマンドライン引数は、sys.argvで得られます。
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」というように使いたいとします。
しかも、「--model_path models」と 「--save False」の順番を変更しても動作させたいとします。 すると,、"model_path"や "save"のそれそれがあるかを調べて、 その直後にある値をパース(規則に従って解析)して得るプログラミングが必要です。 それを簡単に行えるのが、argparse モジュールで、以下の例で示します。
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 -s False -m models と操作すしても同じになります。
上記のように、引数で指定した値が簡単に取得できるようになります。
また、引数で -h または、--help を指定した実行で、次のように使い方を出力してくれます。
$ 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

$


オプション引数による機能がたくさんありますが、以下代表的な機能を、いくつか紹介します。例の結果から意味を推測してください。

dest Namespaceの名前を変更して使う指定

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')

$

default 引数で指定しない場合の値を指定する。

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)

$

type 引数(int, float, bool)の型を指定する。(指定しない場合は、文字列のstrになっている。)

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)

$

action でフラグ的な引数指定が可能になる。

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)

$



urllib.request モジュール( URL を開くための拡張可能なライブラリ)

ウェブスクレイピング(ウェブサイトから情報を抽出するコンピュータソフトウェア技術)などで、使えるモジュールで、以下に簡単な例を示す。
URLが示すファイルを保存する例です。
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)
   
#

スレッド

スレッドでキー入力を行い、それでmainのループを終了する例

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)


threading.Threadで指定時間の経過後に実行する例

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秒後に表示

バイナリを扱う例

bytes型はイミュータブルで要素の変更できない。要素の変更はbytearrayを使う。
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]

numpy で行う。
import numpy as np
b = np.frombuffer(bdata, dtype="int16").tolist() # 上記と同じ結果が得られるnumpyのメソッド
b # 出力:[256, 770, 1284, -513, -257, -1]

バイナリで読み込んで表示する例 以下は 1byte ずつファイルから読み取り、16 進で表示させている例である。
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()

または、1 回の読み取りで可能な限りファイルを読み取ってしまう次の方法もある。
(すべて読み取れとれない可能性もあります)
fr = open("t1321.txt", "br")
bin = fr.read() # 可能な限り読み取る
fr.close()
for i in range(len(bin)):
	print( hex(bin[i]) ) # 各要素の int 値を 16 進文字列で表示

python3.2以降であれば、次のようなbytesからintへの変換メソッドがあります。
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'の表示


structモジュールはフォーマットを指定してバイナリ形式に変換するpackと、復元用unpack間数がある。
(bytesオブジェクトは不変な配列で、8-bit要素で0 <= x < 256 の範囲の整数で記憶する。)
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 pip
Python 2とPython 3の間で大きくシステムが変わりました。
そして、1つのシステムにPython 2とPython 3の両方を入れることもあります。
そして、Python 3ではpipコマンドと同じ動作をするpip3コマンドが用意されました。
Python 2とPython 3の共存環境ではpipがPython 2、pip3がPython 3を使います。
Python 3しか入っていなければ、どちらを呼んでも何も変わりません。