Pythonのメモリ管理と基本文法
Pythonはメモリ管理のためにいくつかの最適化機構を備えている。範囲[-5, 256]の整数は「小整数プール」としてあらかじめキャッシュされ、ガベージコレクションの対象外となる。これより大きな整数は新たにオブジェクトが生成される。また、文字列に対しては「インターン機構」が働き、不変な単一単語などを共有参照させ、参照カウントが0になれば破棄する。ガベージコレクション(GC)については参照カウント方式をベースとしつつ、循環参照を解消するために世代別GCを採用している。オブジェクトは生成時に「0世代」リストに配置され、GC実行時に循環参照のカウントが減らされ、残ったものは「1世代」「2世代」と移行していく。
Python 2では、辞書型のitems()は全てのキーと値のペアを含むリストを返し、iteritems()はイテレータオブジェクトを返すためメモリ効率が良かった。Python 3ではitems()が辞書ビューオブジェクトを返すように変更され、反復可能かつメモリ効率の良い設計となったためiteritems()は削除されている。
乱数生成にはrandomモジュールを用いる。
import random
random_val = random.randrange(1, 100)
代入操作はオブジェクトの参照(メモリアドレス)を渡すのみであり、元のオブジェクトと変更を共有する。copyモジュールのcopy()によるシャローコピーは、コンテナ自体は複製するが、その中身の要素は元のオブジェクトへの参照のままである。一方、copy.deepcopy()を用いたディープコピーは、コンテナおよびその内部にネストされた全ての要素を再帰的に複製するため、完全に独立したオブジェクトとなる。
pass文は何も実行しないプレースホルダーである。構文上ブロックが必要な箇所(クラスや関数の定義など)で、後で実装するための空の枠組みを保ちたい場合や、意図的に何もしないことを明示するために用いられる。
正規表現モジュールにおいて、match()は文字列の先頭からのみマッチングを試み、先頭が不一致なら即座にNoneを返す。対照的にsearch()は文字列全体を走査し、部分一致する最初の箇所を探索する。
文字列の定義には単一引用符と二重引用符が使われ、機能的な差はほぼない。異種の引用符を内包する際にエスケープを省略できる利点がある。三重引用符は、複数行にわたる文字列をそのまま記述でき、ドキュメンテーション文字列(docstring)としてよく利用される。
range()は指定した開始値から終了値までの連続した数値シーケンスを生成する組み込み関数で、forループでの反復処理によく用いられる。Python 3ではイテレータとして振る舞い、メモリを効率的に使用する。
データ構造とアルゴリズムの実装
リストから重複要素を削除する場合、setを用いないアプローチとしては、別のリストを用意して存在確認しながら追加する方法がある。
source_data = ['x', 'y', 'z', 'x', 'y']
unique_items = []
for element in source_data:
if element not in unique_items:
unique_items.append(element)
2つのリストをマージしソート・重複排除を行うカスタムロジックは以下のように実装できる。
arr1 = [2, 3, 8, 4, 9, 5, 6]
arr2 = [5, 6, 10, 17, 11, 2]
merged = arr1 + arr2
result = []
for num in merged:
if num not in result:
result.append(num)
result.sort()
2つのリストを組み合わせて辞書を生成するには、zip関数が便利である。
keys = [10, 20, 30]
values = ['apple', 'banana', 'cherry']
mapped_dict = dict(zip(keys, values))
文字列中から数値を抽出してソート順のキーとするには、sorted()関数のkey引数にカスタムロジックを渡す。正規表現で数字部分を取り出してintにキャストする関数を定義し、それをキーとして用いる。
import re
data = ['room12', 'hall5', 'zone3', '2nd-floor']
def extract_number(text):
match = re.search(r'\d+', text)
return int(match.group()) if match else -1
sorted_data = sorted(data, key=extract_number)
データベースとSQL
Redisの並行アクセス競合に対しては、3つのアプローチが存在する。第一にクライアント側からの対応として、コネクションプーリングを導入し、クライアント内のロック(synchronizedなど)で読み書きを直列化する。第二にサーバー側からの対応として、SETNXコマンドを利用した分散ロックを実装する。第三に、高負荷環境下ではメッセージキューを利用して並行処理を直列化する手法があり、Redisのリスト型などを用いて簡易的なキューとして構築できる。
RedisとMySQLのトランザクションは挙動が異なる。MySQLはSTART TRANSACTIONで開始し、ROLLBACKで巻き戻し、COMMITで確定する(構文エラー以外は部分実行される可能性がある)。対してRedisはMULTIで開始し、DISCARDでキューを破棄(ただし実行済みのロールバックは不可)、EXECで実行する(構文エラーがあれば全体が実行されない)。ロック機構において、MySQLはSELECT ... FOR UPDATEによる悲観的ロックやバージョン管理による楽観的ロックを利用できるが、RedisはWATCHコマンドを用いた楽観的ロックが基本となる。ACID特性のうち、耐久性についてRedisはAOF永続化かつappendfsync always設定の時のみ完全に担保される。
MySQLのストレージエンジンにおいて、MyISAMはトランザクションをサポートせず、高速な読み取りと全文検索に特化している。一方、InnoDBはトランザクションの安全性を保証し、外部キー制約をサポートするため、データの整合性が重要なシステムで広く採用されている。
テーブル結合には主に3種類ある。LEFT JOINは左テーブルの全レコードと、右テーブルの結合キーが一致するレコードを返す。RIGHT JOINはその逆で、右テーブルの全レコードと左テーブルの一致するレコードを返す。INNER JOINは、両テーブルの結合キーが一致するレコードのみを抽出する。
特定の商品が2回以上注文されたproduct_idを抽出するSQLは以下のようになる。
SELECT product_id FROM orders GROUP BY product_id HAVING COUNT(product_id) >= 2;
Webフレームワークとスクレイピング
DjangoはフルスタックのWebフレームワークであり、ORMや管理画面、URLルーティングなどの開発部品を網羅し、MVT(MVC)アーキテクチャに基づき迅速な開発を支援する。一方、TornadoはノンブロッキングI/Oとepollを活用した非同期フレームワークであり、1秒間に数千単位の接続を捌くことができる。そのため、WebSocketやリアルタイム通信を必要とするサービスに最適である。
BeautifulSoupは要素検索のために多数のメソッドを提供している。代表的なものにfind()、find_all()があるほか、階層を遡るfind_parent()やfind_parents()、兄弟要素を探索するfind_next_sibling()、find_previous_sibling()などが存在する。また、前後の要素を走査するfind_next()、find_previous()なども利用可能である。
インフラ・ネットワーク・バージョン管理
Gitでマージ時のコンフリクトが発生した際の対処法は主に3パターンある。ローカルの変更が不要な場合は、git reset --hard origin/mainを実行しリモートの状態で上書きする。ローカルの変更を保持したい場合は、対象ファイルの競合マーカーを手動で編集し、git add後にgit commitを行う。マージ自体を取り消したい場合は、git reset --hard HEADを実行してマージ前の状態に戻す。
HTTPはアプリケーション層のプロトコルであり、クライアント・サーバーモデルに基づく。特徴として、リクエストメソッドとパスだけでアクセスできる簡潔さ、Content-Typeにより任意のデータ形式を扱う柔軟性がある。また、1リクエストごとに接続を切断する「コネクションレス」な性質と、状態を保持しない「ステートレス」な性質を持つ。ステートレスゆえに過去のコンテキストを再送信する必要が生じる場合もあるが、サーバーの設計をシンプルに保つ利点がある。
クライアントからサーバーへ送信されるHTTPリクエストは、主に3つの要素で構成される。要求メソッドや対象パス、HTTPバージョンを含む「リクエストライン」、HostやUser-Agentなどの「ヘッダ」、そしてPOSTリクエストなどで送信される「ボディ(エンティティ)」である。
HTTPSはHTTPにTLS/SSLによる暗号化層を追加したプロトコルである。通信内容が平文であるHTTPに対し、HTTPSは暗号化されるため盗聴や改ざんに強い。また、HTTPはポート80を使用するのに対し、HTTPSはポート443を使用する。HTTPSの導入には認証局(CA)からの証明書発行が必要となることが多い。仕組みとしては、アプリケーション層のデータを直接TCPに渡すのではなく、間にあるTLS/SSL層で暗号化してからTCPに渡すことで安全な通信を実現している。
大容量のテキストファイルから末尾の数行だけを抽出したい場合は、Linuxのtailコマンドを利用する。
tail -n 20 target_file.txt
論理パズルの実装
4人の被疑者(A, B, C, D)のうち1人が犯人である。Aは「私ではない」、Bは「Cが犯人だ」、Cは「Dが犯人だ」、Dは「Cは嘘をついている」と証言した。3人が真実で1人が嘘である場合、犯人を特定するプログラムは以下のようになる。
# Map A->0, B->1, C->2, D->3
for suspect in range(4):
is_truthful = [
suspect != 0, # A's statement
suspect == 2, # B's statement
suspect == 3, # C's statement
suspect != 3 # D's statement
]
if sum(is_truthful) == 3:
print(f"犯人はインデックス {suspect} です")
break