python で辞書から指定の項目のみの辞書を作成する方法のメモ。
> a = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4} > print(a) {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4} > b = {k: a[k] for k in ['a', 'b', 'c']} > print(b) {'a': 0, 'b': 1, 'c': 2}
python でインスタンスのクラス名、メンバ変数を参照する方法のメモ。
インスタンスのクラス名は __class__.__name__ で参照でき、メンバ変数は __dict__ で参照できます。
class Class1: def __init__(self, num, str): self.num = num self.str = str i1 = Class1('abc', 123) i2 = Class1('def', 456) # クラス名 print(i1.__class__.__name__) print(i2.__class__.__name__) # メンバ変数の値 print(i1.__dict__) print(i2.__dict__)
Class1 Class1 {'num': 'abc', 'str': 123} {'num': 'def', 'str': 456}
python で出力ストリームを flush する方法のメモ
print() で flush=True を指定
print('Hello World!', flush=True)
sys.stdout.flush() を実行
print('Hello World!') sys.stdout.flush()
base64 エンコードされた画像を Cloud Storage にアップロードする方法のメモ。
プログラム
# usage: uplaod_base64_image_to_gcs.py {bucket} {dir} < {json} import sys import base64 import json from google.cloud import storage def upload_to_gcs(bucket, dir, obj): img_bytes = base64.b64decode(obj['image_base64']) blob = bucket.blob(f"{dir}/{obj['file_name']}") blob.upload_from_string(img_bytes, content_type='image/jpeg') def main(): gcs_bucket = sys.argv[1] gcs_dir = sys.argv[2] client = storage.Client() bucket = client.bucket(gcs_bucket) for line in sys.stdin: obj = json.loads(line) upload_to_gcs(bucket, gcs_dir, obj) return 0 if __name__ == '__main__': res = main() exit(res)
データ
$ cat data.jsonl {"id":"01","file_name":"01.jpg","image_base64":"/9j/4AAQSkZJ..."} {"id":"02","file_name":"02.jpg","image_base64":"/9j/4AAQSkZJ..."}
プログラム実行・実行結果確認
$ cat data.jsonl | python upload_base64_image_to_gcs.py gcs-bucket-001 images $ gsutil ls -L gs://gcs-bucket-001/images/*.jpg gs://gcs-bucket-001/images/01.jpg: ... Storage class: STANDARD Content-Length: 28300 Content-Type: image/jpeg ... gs://gcs-bucket-001/images/02.jpg: ... Storage class: STANDARD Content-Length: 21648 Content-Type: image/jpeg ...
python で画像を base64 エンコードする方法のメモ。
プログラム
import sys import io import base64 import json def read_image_file(image_file): with open(image_file, 'rb') as inst: image = inst.read() return image return None def main(): for i in range(1, len(sys.argv)): image_file = sys.argv[i] image = read_image_file(image_file) image_bytes = io.BytesIO(image).read() image_base64 = base64.b64encode(image_bytes).decode('utf-8') obj = { 'id': i, 'image_base64': image_base64, } print(json.dumps(obj, ensure_ascii=False)) return 0 if __name__ == '__main__': res = main() exit(res)
実行結果
$ python image_base64.py img1.jpg img2.jpg {"id": 1, "file_name": "img1.jpg", "image_base64": "/9j/4AA..."} {"id": 2, "file_name": "img2.jpg", "image_base64": "/9j/4AA..."}
ドラッグ&ドロップでアップロードする画像を指定し、画像をサーバに送信します。
サーバは python の flask を使って作成します。
※テンプレートファイルが html と解釈されてしまっています。
ファイル構成
. ├── image_controller.py ├── image_processor.py ├── image_server.py └── template ├── index.html └── upload.html
サーバ本体: image_server.py
from flask import Flask, render_template from image_controller import ImageController gconfig = { 'port': 5001, 'template': { 'folder': 'template', }, 'index': { 'url': '/intra/test/upload_image/', 'template': 'index.html', }, 'upload': { 'url': '/intra/test/upload_image/upload', 'template': 'upload.html', } } app = Flask(__name__, template_folder=gconfig['template']['folder']) @app.route(gconfig['index']['url'], methods=["e;GET"e;]) def view_index(): html = render_template(gconfig['index']['template']) return html @app.route(gconfig['upload']['url'], methods=["e;POST"e;]) def view_upload(): ctrl = ImageController(gconfig) resp_obj = ctrl.upload() html = render_template( gconfig['upload']['template'], title=resp_obj['title'], image_type=resp_obj['image_type'], image_base64=resp_obj['image_base64'] ) return html def main(): app.run(port=gconfig['port'], host='0.0.0.0') return 1 if __name__ == '__main__': res = main() exit(res)
コントローラ: image_controller.py
from flask import request from image_processor import ImageProcessor class ImageController: def __init__(self, config): self.config = config self.processor = ImageProcessor(config) def upload(self): params = {} params['title'] = request.form.get('title', '') params['image'] = request.files.get('image').stream.read() #print(params['image']) resp_obj = self.processor.upload(params) return resp_obj
処理: image_processor.py
import io import base64 import imghdr class ImageProcessor: def __init__(self, config): self.config = config def upload(self, params): image_base64 = base64.b64encode(params['image']).decode('utf-8') image_type = imghdr.what(io.BytesIO(params['image'])) obj = { 'title': params['title'], 'image_type': f'image/{image_type}', 'image_base64': image_base64, } return obj
画像アップロード画面テンプレート: index.html
<!DOCTYPE html> <html lang="e;ja"e;> <head> <title>drag & drop image</title> </head> <body> <form method="e;POST"e; action="e;upload"e; enctype="e;multipart/form-data"e;> <input id="e;id_input"e; type="e;file"e; name="e;image"e; accept="e;image/*"e; hidden> <input id="e;id_title"e; type="e;text"e; name="e;title"e; size="e;40"e;><button id="e;id_remove"e; type="e;button"e;>削除</button> <button id="e;id_submit"e; type="e;submit"e;>送信</button> </form> <script> const uploadObj = document.getElementById("e;id_upload"e;); const previewObj = document.getElementById("e;id_preview"e;); const noImageObj = document.getElementById("e;id_no_image"e;); const imageInputObj = document.getElementById("e;id_input"e;); const removeObj = document.getElementById("e;id_remove"e;); const submitObj = document.getElementById("e;id_submit"e;); // クリック時にはファイル選択 uploadObj.addEventListener("e;click"e;, () => imageInput.click()); // プレビュー表示 imageInputObj.addEventListener("e;change"e;, (e) => { const file = e.target.files[0]; if (!file) return; previewObj.removeAttribute("e;hidden"e;); previewObj.src = URL.createObjectURL(file); }, false); // uploadObj.addEventListener("e;dragover"e;, (e) => { e.stopPropagation(); e.preventDefault(); uploadObj.style.background = "e;#cccccc"e;; }); // uploadObj.addEventListener("e;dragleave"e;, (e) => { e.stopPropagation(); e.preventDefault(); uploadObj.style.background = "e;#ffffff"e;; }); // ドロップ uploadObj.addEventListener("e;drop"e;, (e) => { e.stopPropagation(); e.preventDefault(); uploadObj.style.background = "e;#ffffff"e;; const files = e.dataTransfer.files; if (files.length > 1) return; imageInputObj.files = files; previewObj.removeAttribute("e;hidden"e;); previewObj.src = URL.createObjectURL(imageInputObj.files[0]); }); // 削除 removeObj.addEventListener("e;click"e;, (e) => { previewObj.setAttribute("e;hidden"e;, true); previewObj.src = "e;"e;; }); </script> </body> </html>
サーバレスポンステンプレート: upload.html
<html> <head> </head> <body>画像アップロード
{{ title }}</body> </html>
python で imghdr による画像形式の判定する方法のメモ。
ここでは画像ファイル名で画像を指定した場合と、画像データを指定した場合の判定方法を検証します。
import sys import io import imghdr def read_image_file(image_file): image = None with open(image_file, 'rb') as inst: image = inst.read() return image def main(): image_file = sys.argv[1] # 画像ファイルで判定 res = imghdr.what(image_file) print(f'image file: {res}') # 画像バイトデータで判定 image = read_image_file(image_file) res = imghdr.what(io.BytesIO(image)) print(f'image data: {res}') return 0 if __name__ == '__main__': res = main() exit(res)
jpg ファイル、png ファイルの画像判定結果では、それぞれ正しく判定しています。
$ python test_imghdr.py jpg1.jpg image file: jpeg image data: jpeg $ python test_imghdr.py png1.png image file: png image data: png
jpg ファイルの拡張子を png に変更しても、正しく判定することができます。
$ python test_imghdr1.py jpg1.png image file: jpeg image data: jpeg
python で例外のメッセージを strerr に出力する方法のメモ。
print({例外}, file=sys.stderr) で例外を stderr に出力することができます。
import sys import json; try: a = '[0, 1, 2' obj = json.loads(a) except Exception as e: print(e, file=sys.stderr)
実行結果
Expecting ',' delimiter: line 1 column 9 (char 8)
str() で例外オブジェクトを文字列化してから出力することもできます。
import sys import json; try: a = '[0, 1, 2' obj = json.loads(a) except Exception as e: sys.stderr.write(str(e) + '\n')
出力結果
Expecting ',' delimiter: line 1 column 9 (char 8)
python の json5 ライブラリの利用方法のメモ。
json5 では以下のような json としてはエラーになる文字列でもエラーになりません。
インストール
pip install json5
json5 での parse
> import json5 > a = '{"a": 123, "b": 456, }' > json5.loads(a) {'a': 123, 'b': 456} > b = '[1, 2, ]' > json5.load2(b) [1, 2]
json5 での文字列化
> a = '{"a-b": 1, "a_b": 2}' > obj = json5.loads(a) > json5.dumps(obj) '{"a-b": 1, a_b: 2}'
pyenv による python のインストールメモ。
pyenv のインストール
準備
sudo yum install git
pyenv のインストール
curl https://pyenv.run | bash
python のインストール
準備
sudo yum install gcc sudo yum install g++ sudo yum install gcc-c++ sudo yum install zlib-devel sudo yum install openssl-devel sudo yum install bzip2-devel sudo yum install xz-devel sudo yum install ncurses-devel sudo yum install libffi-devel sudo yum install sqlite-devel sudo yum install readline-devel
インストール可能な python のバージョンを確認
pyenv install --list
python のインストール
pyenv install 3.12.5
Downloading Python-3.12.5.tar.xz... -> https://www.python.org/ftp/python/3.12.5/Python-3.12.5.tar.xz Installing Python-3.12.5... Installed Python-3.12.5 to /home/{...}/.pyenv/versions/3.12.5
利用可能な python のバージョンを表示
pyenv versions
* system (set by /home/{...}/.pyenv/version) 3.12.5
python のバージョンを選択
pyenv global 3.12.5
pyenv versions
system * 3.12.5 (set by /home/{...}/.pyenv/version)
python で文字列の先頭を指定バイト以内で切り出す方法のメモ。
単純に指定バイト数で文字列の先頭を取得すると、日本語のマルチバイト文字が途中で切れてしまうため、文字が途中で切れないように確認しながら先頭文字列を取得します。。
import io def get_head_by_bytes(str, max_bytes, encoding='utf-8'): buf = io.BytesIO() buf_len = 0 str_len = len(str) for c in str: b = c.encode(encoding) b_len = len(b) if buf_len + b_len <= max_bytes: buf.write(b) buf_len += b_len else: break bytes = buf.getvalue() buf.close() out_str = bytes.decode(encoding) return out_str def main(): strs = [ "ビール!麦酒!", "ビール!beer!麦酒!", ] for str in strs: head = get_head_by_bytes(str, 15) num_bytes = len(head.encode('utf-8')) print(f'''org: {str}''') print(f'''head: {head}({num_bytes})''') return 0 if __name__ == '__main__': res = main() exit(res)
実行結果
org: ビール!麦酒! head: ビール!麦(13) org: ビール!beer! head: ビール!beer!(15)
import sys from PIL import Image def main(): in_file = sys.argv[1] out_file = sys.argv[2] rate = float(sys.argv[3]) img = Image.open(in_file) out_width = int(img.width * rate) out_height = int(img.height * rate) out_img = img.resize((out_width, out_height)) out_img.save(out_file) return 0 exit(main())
import xlsxwriter class ExcelConverter: def __init__(self, fname): self.workbook = xlsxwriter.Workbook(fname) self.worksheet = self.workbook.add_worksheet() # 赤・ボールド self.strong = self.workbook.add_format({'color': 'red', 'bold': True}) # 上・左詰め・折り返し self.cell_format = self.workbook.add_format() self.cell_format.set_text_wrap() self.cell_format.set_align('left') self.cell_format.set_align('top') self.data_idx = 0 self.row = 0 # ヘッダ行を出力する def output_header(self): self.row += 1 cell = f'A{self.row}' self.worksheet.write(cell, '行番号') cell = f'B{self.row}' self.worksheet.write(cell, 'データ') # データを出力する def output_data(self, obj): self.data_idx += 1 self.row += 1 # 行番号 cell = f'A{self.row}' self.worksheet.set_column(f'{cell}:{cell}', 7, self.cell_format) self.worksheet.write(cell, self.data_idx) # データ cell = f'B{self.row}' self.worksheet.set_column(f'{cell}:{cell}', 15, self.cell_format) self.worksheet.write(cell, obj['product-id']) def close(self): self.workbook.close() def main(): out_fname = sys.argv[1] conv = ExcelConverter(out_fname) conv.output_header() for line in sys.stdin: try: obj = json.loads(line) conv.output_data(obj) except Exception as e: try: sys.stderr.write(json.dumps(obj, ensure_ascii=False) + '\n') sys.stderr.write(e) sys.stderr.write('\n') except: pass conv.close()