potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

Python 3.8 チップス

2021/3/10:この記事は別のブログで投稿した記事を移動したものです。

Python3を触っていてエラーが発生したり調べたことのひたすらメモです。短いもの主体なのでチップスの名前を使っています。

arrayはリスト内包記法でリストに変換される

from array import array
array1 = array("i", [0, 1, 2, 3, 4])
print(array1) #array('i', [0, 1, 2, 3, 4])
print([i for i in array1]) #[0, 1, 2, 3, 4]
print(type([i for i in array1])) #<class 'list'>

ctypesにはmemmoveが実装されている

from ctypes import *
ctypes.memmove #<CFunctionType object at ...>

RtlCopyMemoryやRtlMoveMemoryは不要です。

arrayは文字列をサポート終了予定

ctypes.get_unicode_bufferメソッドの戻り値に対応する型はctypes.c_wchar_p

ctypes.get_string_bufferメソッドの戻り値に対応する型はctypes.c_char_p

ctypes.c_int/c_uint系のvalueはすべてint型

https://docs.python.org/ja/3/library/ctypes.html

import ctypes
print([ctypes.c_int16(12345).value, type(ctypes.c_int16(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_uint16(12345).value, type(ctypes.c_uint16(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_int32(12345).value, type(ctypes.c_int32(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_uint32(12345).value, type(ctypes.c_uint32(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_int64(12345).value, type(ctypes.c_int64(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_uint64(12345).value, type(ctypes.c_uint64(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_int(12345).value, type(ctypes.c_int(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_uint(12345).value, type(ctypes.c_uint(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_long(12345).value, type(ctypes.c_long(12345).value)]) #[12345, <class 'int'>]
print([ctypes.c_ulong(12345).value, type(ctypes.c_ulong(12345).value)]) #[12345, <class 'int'>]

ctypesでバイト配列を扱うには(c_byte*size).from_buffer(...)を使う

import ctypes
buffer = bytearray(100)
ctypes.memmove((ctypes.c_byte*100).from_buffer(buffer), destination, 100)

参考:https://stackoverflow.com/questions/37422662/how-can-i-use-ctypes-to-pass-a-bytearray-into-a-c-function-that-takes-a-char-as

久しぶりにPhyton 3を使用したときに調べて使ったコード断片(スニペット)のメモです。

ディレクトリの存在を保証する

import os
os.makedirs("dir", exists_ok=True)

exists_ok=Trueを指定してos.makedirs関数を使用します。この呼び出しはディレクトリが存在すれば何もせず、存在しない場合は新しく作成します。

ジェネレーターをリストに変換する

generator = (i % 2 for i in range(100))
print(generator) #<generator object <genexpr> at ~>
print(list(generator)) #[0, 1, 0, 1, 0, 1, 0, ...]

list関数を使用します。

ジェネレーターの最初の要素を取得する

generator = (i % 2 for i in range(100))
print(next(generator)) #0

next関数を使用します。

文字列のリストから特定文字列からはじまる文字列のリストを作成する

strings = ["aaa", "bbb", "ccc", "ddd", "eee", "aabb"]
print(list(filter(lambda string: string.startswith("aa"), strings)))
# ['aaa', 'aabb']

filter関数とlambdaを使用します。ジェネレーターのまま保持する場合はlist関数を適用しません。

文字列のリストから特定文字列で終わる文字列のリストを作成する

strings = ["aaa", "bbb", "ccc", "ddd", "eee", "aabb"]
print(list(filter(lambda string: string.endswith("bb"), strings)))
# ['bbb', 'aabb']

filter関数とlambdaを使用します。ジェネレーターのまま保持する場合はlist関数を適用しません。

URLからファイルをダウンロードする

import time
import urllib.request
url = ...
filename = ...
urllib.request.urlretrieve(url, filename)

time.sleep(0.5) #連続アクセスする場合はsleep関数の適用を推奨します。

EUC-JPエンコードのHTMLファイルをBeautifulSoup4で開く

html.parser版

from bs4 import BeautifulSoup
filename = ...
with open(filename, "r", encoding="euc-jp") as f:
    doc = BeautifulSoup(f, "html.parser")

lxml版

from bs4 import BeautifulSoup
filename = ...
with open(filename, "r", encoding="euc-jp") as f:
    doc = BeautifulSoup(f, "lxml")

BeautifulSoup4である文字列から始まるTD要素の2番目の兄弟TD要素を取得する

from bs4 import BeautifulSoup
with open(..., "r", encoding=...) as f:
    doc = BeautifulSoup(f, "html.parser")
td1 = next(filter(lambda element: element.string.startswith(...),
    doc.select("table.classname")))
td2 = td1.parent.select_one("td:nth-of-type(2)")

next_elementやnext_siblingsでは取得できなかったのでparentを経由しました。

辞書のキーと値を文字列へ変換する

kwargs = dict(...)
{str(kwarg[1]):str(kwarg[0]) for kwarg in kwargs}

辞書の値を文字列へ変換する

kwargs = dict(...)
{kwarg[1]:str(kwarg[0]) for kwarg in kwargs}

辞書のキーを文字列へ変換する

kwargs = dict(...)
{str(kwarg[1]):kwarg[0] for kwarg in kwargs}

正規表現で同じアルファベットの連続をマッチする

import re
re.match("^\s*(?P<az>[A-Z])((?P=az)*)\s*$", string1)
import re
print(re.match("^\s*(?P<az>[A-Z])((?P=az)*)\s*$", "A"))    #<re.Match object; span=(0, 1), match='A'>
print(re.match("^\s*(?P<az>[A-Z])((?P=az)*)\s*$", "AAAA")) #<re.Match object; span=(0, 4), match='AAAA'>
print(re.match("^\s*(?P<az>[A-Z])((?P=az)*)\s*$", "AB"))   #None
print(re.match("^\s*(?P<az>[A-Z])((?P=az)*)\s*$", "ABA"))  #None
print(re.match("^\s*(?P<az>[A-Z])((?P=az)*)\s*$", "0"))    #None
print(re.match("^\s*(?P<az>[A-Z])((?P=az)*)\s*$", "あ"))   #None

辞書のリストからキーが条件を満たす項目からなる辞書のリストを作成する

#辞書のリストからキーが["b", "d"]に含まれる項目からなる辞書のリストを作成する
dict_list = [{"a":0, "b":1, "c":2, "d":3}, {"a":0, "b":1, "c":2, "f":3}, {"b":0, "d":1, "c":2, "k":3}]
list(map(lambda d: dict(filter(lambda item: item[0] in ["b", "d"], d.items())), dict_list))
#[{'b': 1, 'd': 3}, {'b': 1}, {'b': 0, 'd': 1}]
#辞書のリストから値が2の倍数の項目からなる辞書のリストを作成する
dict_list = [{"a":0, "b":1, "c":2, "d":3}, {"a":0, "b":1, "c":2, "f":3}, {"b":0, "d":1, "c":2, "k":3}]
list(map(lambda d: dict(filter(lambda item: item[1] % 2 == 0, d.items())), dict_list))
#[{'a': 0, 'c': 2}, {'a': 0, 'c': 2}, {'b': 0, 'c': 2}]

アルファベットの距離を計算する

"Z".encode()[0] - "A".encode()[0]