こんにちはヤク学長です。
データサイエンティスト兼ファーマシストで、アルゴリズムやBI開発を行っています。

本記事の目的は、「pythonの基本操作を知る」ことを目的としています。

【ステップアップ】「Pythonの実践」簡単速習‼【インフラ構築自動化/応用⑦】

【本記事のもくじ】

まず、「Python」に真剣に取り組むための概要を解説します。
下記の方法で、簡単に概要を抑えることができます。

  • 1.Pythonの便利ツール

それでは、上から順番に見ていきます。
なお、本上記の方法を順番に抑えれば成果が出ます。

記事の内容は「転載 & 引用OK」問題ありません。

1.Pythonの便利ツール

IPython

IPythonは、対話型のPythonシェルの強化版で、豊富な機能を持っているPython開発者にとって非常に便利なツールです。IPythonは、Pythonの基本シェルに比べて多くの機能を持っています。

IPythonの主な機能には、以下が含まれます。

  • 履歴の保存と再利用
  • 強力なコマンド補完機能
  • オブジェクトの自動表示
  • システムコマンドの直接実行
  • マジックコマンドの使用
  • プロファイリングツールの使用
  • 独自の機能を拡張するための拡張性

IPythonは、Pythonプログラマーにとって非常に便利なツールであり、開発効率を向上させることができます。

IPythonを使用する

IPythonを使用するには、まずipythonパッケージをインストールする必要があります。インストールするには、以下のようにコマンドを実行します。

pip install ipython

インストールが完了したら、IPythonを起動するには、ターミナルでipythonと入力してEnterキーを押します。

IPythonを起動すると、以下のようなプロンプトが表示されます。

In [1]:

これはIPythonの対話モードで、Pythonのコードを入力して実行することができます。例えば、以下のように入力してみましょう。

In [1]: print("Hello, IPython!")

Enterキーを押すと、次のような出力が表示されます。

Hello, IPython!

また、IPythonにはいくつかの便利な機能が用意されています。例えば、以下のように?を付けて関数名を入力すると、その関数のドキュメントを表示することができます。

In [2]: len?

Enterキーを押すと、len関数のドキュメントが表示されます。

IPythonには、通常のPythonとは異なる様々な機能があります。詳しくは、公式ドキュメントを参照してください。

contexlib.contexmanager

contextlibモジュールのcontextmanagerデコレータを使用することで、関数をコンテキストマネージャに変換することができます。これにより、withステートメントの使用ができるようになります。

例えば、以下のようなコンテキストマネージャを実装することができます。

from contextlib import contextmanager

@contextmanager
def my_context_manager():
# マネージャ開始時に実行する処理
print("Start my_context_manager()")
try:
# withブロックで実行される処理
yield
finally:
# マネージャ終了時に実行する処理
print("End my_context_manager()")

このコードでは、contextmanagerデコレータを使用して、my_context_manager()関数をコンテキストマネージャに変換しています。yieldを含むブロックが、withステートメント内で実行されます。

以下は、my_context_manager()を使用する例です。

with my_context_manager():
# withブロック内で実行する処理
print("Hello, world!")

このコードを実行すると、以下の出力が得られます。

Start my_context_manager()
Hello, world!
End my_context_manager()

contexlib.conte

contextlib.contextmanagerは、Pythonの標準ライブラリのcontextlibモジュールに含まれるデコレーターです。このデコレーターを使用することで、特定の関数を「コンテキストマネージャー」として使用できます。

コンテキストマネージャーとは、リソース(ファイル、ソケット、ロックなど)を簡単に開いたり閉じたりできるようにするためのPythonの機能です。通常、リソースはtry-finally文で開いたり閉じたりしますが、contextlib.contextmanagerを使用することで、より簡潔で読みやすいコードを書くことができます。

contextlib.contextmanagerデコレーターを使用すると、コンテキストマネージャーを定義するための関数を作成できます。この関数は、ジェネレーターとして実装する必要があります。ジェネレーター内のyield文の前のコードは、with文が開始されたときに実行され、yield文の後のコードは、withブロックから抜けたときに実行されます。

以下は、contextlib.contextmanagerを使用して、ファイルを開いて閉じるコンテキストマネージャーを定義する例です。

import contextlib

@contextlib.contextmanager
def file_open(file_path):
try:
file = open(file_path, 'r')
yield file
finally:
file.close()

この例では、ファイルを開くためのコンテキストマネージャーを作成しています。この関数は、try-finally文でファイルを開いたり閉じたりする必要がなくなり、ファイルの読み書きができるようになります。以下は、このコンテキストマネージャーを使用して、ファイルを読み込む例です。

with file_open('example.txt') as f:
for line in f:
print(line)

この例では、file_open関数を使用して、’example.txt’というファイルを開き、各行を読み取っています。withブロックを抜けると、ファイルは自動的に閉じられます。

contextmanager

contextmanagercontextlib モジュールにあるデコレータで、クラスを定義することなく、簡単にコンテキストマネージャーを作成することができます。

以下は、contextmanagerデコレータを使用した簡単な例です。

from contextlib import contextmanager

@contextmanager
def my_context():
# マネージャに入る前に実行されるコード
print('Enter my_context')
# マネージャに入るためにyieldする
yield

# マネージャを出た後に実行されるコード
print('Exit my_context')

上記の例では、 my_context関数を@contextmanagerデコレータで修飾し、 yieldキーワードでマネージャの中身を区切ります。 例えば、マネージャ内で必要な処理を行うことができます。 上記の例では、ただ Enter my_contextExit my_context を表示しているだけですが、必要に応じて、ファイルを開いたり、ロックを獲得したりすることができます。

次に、my_contextを使用する例を示します。

with my_context():
print('Hello from my_context')

上記の例では、 withステートメントを使用して、my_contextのコンテキスト内でprint文を呼び出しています。 このコードを実行すると、以下の出力が得られます。

Enter my_context
Hello from my_context
Exit my_context

以上が、 contextmanagerデコレータの基本的な使用法の例です。

contexlib.ContexDecorater

contextlib.ContextDecorator は、 contextlib.ContextManager のサブクラスで、__enter__ および __exit__ メソッドを定義することで、特定のコンテキストマネージャを簡単に作成できる便利なデコレーターです。

ContextDecorator を使用すると、既存のコンテキストマネージャをデコレートして、呼び出し元の関数の実行中に自動的にセットアップとクリーンアップを行うことができます。

たとえば、以下のような ContextDecorator を定義することができます。:

from contextlib import ContextDecorator

class my_decorator(ContextDecorator):
def __enter__(self):
# セットアップ処理
return self

def __exit__(self, exc_type, exc_value, traceback):
# クリーンアップ処理
return False

これにより、関数をデコレートすることができます。

@my_decorator()
def my_function():
# 何らかの処理
pass

このようにデコレートすることで、関数 my_function() が呼び出されると、自動的に my_decorator オブジェクトが作成され、__enter__() メソッドが呼び出され、その後関数の本体が実行されます。関数が完了すると、__exit__() メソッドが呼び出され、コンテキストがクリーンアップされます。

ContextDecorator は、 contextlib モジュールによって提供されるコンテキストマネージャを簡単に利用するための便利なデコレーターです。通常、既存のコンテキストマネージャを変更したくない場合に使用されます。また、ContextDecorator を使用することで、 with 文を使用せずにコンテキストマネージャを呼び出すこともできます。

contexlib.suppress

contextlib.suppressは、指定した例外を捕捉し、何もせずに無視するコンテキストマネージャを提供する標準ライブラリのモジュールです。

通常、Pythonのtry-except文を使用すると、例外をキャッチするために多くの行が必要になる場合があります。しかし、このモジュールを使用すると、1行で簡潔に例外を無視することができます。以下は、例外を無視する例です。

import contextlib
with contextlib.suppress(FileNotFoundError):
os.remove('file.txt')

上記の例では、FileNotFoundErrorが発生しても、何も起こりません。エラーが発生しなければ、通常通り実行が続行されます。

contexlib.redirect_stdoutとcontexlib.redict_sterr

contextlib.redirect_stdout および contextlib.redirect_stderr は、標準出力または標準エラー出力を一時的に別のファイルにリダイレクトするために使用されます。これらのコンテキストマネージャは、 with ステートメントを使用して呼び出されます。 with ブロック内のコードによって出力されるすべてのものが、指定されたファイルに書き込まれます。

redirect_stdoutredirect_stderr を使用すると、例外が発生した場合にエラーメッセージをログに記録したり、システムにエラーメッセージを表示する前に処理を行うことができます。

以下は、 redirect_stdout の具体例です。この例では、標準出力を一時的にファイルにリダイレクトして、結果をファイルに書き込んでいます。

import contextlib
import io
with io.StringIO() as output, contextlib.redirect_stdout(output):
print("Hello, World!")
result = output.getvalue()
print(result)

contexlib.ExitStack

contextlib.ExitStack は、Pythonのコンテキストマネージャを効果的にネストして管理するためのクラスです。このクラスを使用すると、複数のコンテキストマネージャを一度に扱うことができます。ExitStack クラスは、Python 3.3で導入されました。

通常、コンテキストマネージャはネストされます。たとえば、あるファイルを開いて、そのファイルを読み込んで、最後にそのファイルを閉じるようにするには、次のようにネストされたコンテキストマネージャを使用できます。

with open('file.txt') as f:
with contextlib.suppress(IOError):
data = f.read()

これは機能しますが、ネストが深くなると、コードが読みにくくなり、修正が難しくなります。ここで ExitStack クラスが役立ちます。ExitStack クラスを使用すると、複数のコンテキストマネージャを一度に扱うことができます。

たとえば、次のコードは、ExitStack クラスを使用して、複数のファイルを一度に開いて、ファイルを閉じます。

with contextlib.ExitStack() as stack:
files = [stack.enter_context(open(f)) for f in ['file1.txt', 'file2.txt', 'file3.txt']]
# Do something with the files here

このコードでは、3つのファイルを開きます。ファイルがリストにあるので、括弧を使用してリスト内包表記を作成して、複数のファイルを一度に開くことができます。ExitStack クラスは、開いたファイルを自動的に閉じます。

ioストリーム

Pythonのioモジュールは、ファイルのようなストリーム操作を実現するための機能を提供します。このモジュールには、テキストモードやバイナリモードでストリームを読み書きするためのクラスや関数が含まれています。

例えば、io.StringIOクラスは、文字列をファイルのように扱えるようにします。以下は、このクラスを使用して、文字列を読み書きする例です。

import io

# 文字列を書き込む
sio = io.StringIO()
sio.write("Hello, world!")
sio.seek(0)

# 文字列を読み込む
data = sio.read()
print(data)

また、ioモジュールには、ファイルのようなストリームを操作するための関数もあります。例えば、io.open関数は、テキストモードやバイナリモードでファイルを開くことができます。以下は、この関数を使用して、テキストファイルを読み込む例です。

import io

# テキストファイルを読み込む
with io.open("text.txt", mode="r", encoding="utf-8") as f:
data = f.read()
print(data)

この例では、io.open関数を使用して、”text.txt”という名前のファイルをテキストモードで開いています。mode引数には、ファイルを開くモードを指定し、encoding引数には、ファイルのエンコーディングを指定しています。with文を使用することで、ファイルを自動的に閉じることができます。

collections.ChinMap

collections.ChinMap は、Pythonのデータ型の1つで、 dict のサブクラスです。通常の dict とは異なり、ChinMapはキーの比較にユニコードの正規化形式を使います。これは、複数の異なるUnicode表現で同じ文字列を表現できるため、異なる表現を持つ文字列を区別しないようにするためです。

以下は、ChinMapを使用する例です。まず、ChinMapをインポートします。

from collections import ChainMap

次に、2つの dict オブジェクトを作成します。

dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}

これらの dict オブジェクトを、 ChainMap に渡して連結します。

chain_map = ChainMap(dict1, dict2)

これで、 chain_map は、 dict1dict2 を連結したものです。 chain_map は、まず dict1 を検索し、その次に dict2 を検索します。つまり、 b の値は dict1 によって 2 に設定され、これで、 chain_map は、 dict1dict2 を連結したものです。 chain_map は、まず dict1 を検索し、その次に dict2 を検索します。つまり、 b の値は dict1 によって 2 に設定され、 c の値は dict2 によって 4 に設定されます。 c の値は dict2 によって 4 に設定されます。

print(chain_map['a']) # 1
print(chain_map['b']) # 2
print(chain_map['c']) # 4

ChainMap は、 dict オブジェクトのリストを連結することもできます。以下はその例です。

dict3 = {'c': 5, 'd': 6}
chain_map = ChainMap(dict1, dict2, dict3)

この場合、 chain_map は、 dict1dict2dict3 を順番に検索します。つまり、 c の値は dict2 によって 4 に設定され、 d の値は dict3 によって 6 に設定されます。

print(chain_map['a']) # 1
print(chain_map['b']) # 2
print(chain_map['c']) # 4
print(chain_map['d']) # 6

collections.dafaultdict

collections.defaultdict は、Pythonのデータ型の1つで、通常の dict と似ていますが、存在しないキーにアクセスした場合に新しい値を返すことができます。このデータ型は、特に辞書の値をリストやセットなどのコレクションに設定する場合に便利です。

defaultdictを使用するには、まず collections モジュールをインポートします。

from collections import defaultdict

次に、defaultdict オブジェクトを作成します。以下の例では、int を引数に渡すことで、新しい要素には 0 が自動的に設定されるようにしています。

my_dict = defaultdict(int)

このように作成した my_dict は、通常の dict と同様に使用できます。しかし、存在しないキーにアクセスすると、自動的に 0 が返されます。

print(my_dict['key']) # 0

例えば、以下のように my_dict に要素を追加することができます。

my_dict['key1'] = 1
my_dict['key2'] = 2

my_dict を出力すると、以下のようになります。

print(my_dict) # defaultdict(<class 'int'>, {'key': 0, 'key1': 1, 'key2': 2})

defaultdict は、存在しないキーにアクセスした場合に、自動的に新しい値を設定することができるため、リストなどのコレクションを要素とする辞書を作成する際に特に便利です。例えば、以下のように、defaultdict を使用して、リストを値とする辞書を作成することができます。

my_dict = defaultdict(list)
my_dict['fruits'].append('apple')
my_dict['fruits'].append('banana')
my_dict['fruits'].append('orange')
print(my_dict['fruits']) # ['apple', 'banana', 'orange']

このように、defaultdict を使用することで、簡単に新しいキーに対して初期値を設定することができます。

collections.Counter

collections.Counter は、Pythonのデータ型の1つで、リストや文字列などのイテラブルなオブジェクトから要素の出現回数をカウントするための便利なクラスです。collections モジュールをインポートして使用します。

まず、Counter オブジェクトを作成します。以下の例では、文字列から要素の出現回数をカウントしています。

from collections import Counter

s = 'hello world'
counter = Counter(s)
print(counter)

出力結果は以下の通りになります。

Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})

Counter オブジェクトには、要素とその出現回数が辞書のように格納されています。この例では、文字列 s には ‘l’ が3つ、’o’ が2つ、’h’、’e’、’ ‘、’w’、’r’、’d’ がそれぞれ1つ含まれています。

Counter オブジェクトには、通常の辞書と同じように、キーに対する値にアクセスすることができます。例えば、以下のように、’l’ の出現回数を取得することができます。

print(counter['l'])

出力結果は以下の通りになります。

また、Counter オブジェクトは、要素の出現回数を自動的にカウントするため、リストなどのイテラブルなオブジェクトから出現回数を簡単にカウントすることができます。例えば、以下のように、リストから要素の出現回数をカウントすることができます。

lst = ['apple', 'banana', 'orange', 'banana', 'apple', 'apple']
counter = Counter(lst)
print(counter)

出力結果は以下の通りになります。

Counter({'apple': 3, 'banana': 2, 'orange': 1})

Counter オブジェクトは、要素の出現回数をカウントするための便利なクラスであり、集計や出現回数の多い要素の取得など、さまざまな用途に使用することができます。

collections.deque

collections.deque は、Pythonのデータ型の1つで、双方向キュー (deque, double-ended queue) を表現するためのクラスです。collections モジュールをインポートして使用します。

まず、deque オブジェクトを作成します。以下の例では、空の deque オブジェクトを作成しています。

from collections import deque

d = deque()

deque オブジェクトには、要素を追加するための append() メソッドや、先頭に要素を追加するための appendleft() メソッド、末尾の要素を削除するための pop() メソッドや、先頭の要素を削除するための popleft() メソッドなどがあります。例えば、以下のように、append() メソッドを使って要素を追加することができます。

d.append(1)
d.append(2)
d.append(3)
print(d)

出力結果は以下の通りになります。

deque([1, 2, 3])

また、deque オブジェクトは、先頭や末尾に要素を追加したり、削除したりすることができます。例えば、以下のように、appendleft() メソッドを使って先頭に要素を追加することができます。

d.appendleft(0)
print(d)

出力結果は以下の通りになります。

deque([0, 1, 2, 3])

同様に、以下のように、popleft() メソッドを使って先頭の要素を削除することができます。

d.popleft()
print(d)

出力結果は以下の通りになります。

deque([1, 2, 3])

deque オブジェクトは、スタック (後入れ先出し) やキュー (先入れ先出し) として使用することができます。また、大量の要素を処理する場合には、list オブジェクトよりも高速に処理することができます。deque オブジェクトは、Pythonの標準ライブラリに含まれているので、インストールする必要はありません。

collections.namedtuple

collections.namedtuple は、Pythonのデータ型の1つで、タプルに名前をつけたい場合に使用するクラスです。collections モジュールをインポートして使用します。

namedtuple を使用すると、通常のタプルと同様に、不変 (immutable) なオブジェクトを作成することができます。ただし、各要素に名前をつけることができるため、タプルの各要素に直接アクセスできるようになります。これにより、タプルの要素を直接扱う場合に生じる、要素の位置を誤るミスを回避することができます。

以下は、namedtuple を使用して、カラーコードを表すタプルを定義する例です。

from collections import namedtuple

Color = namedtuple('Color', ['red', 'green', 'blue'])

この例では、namedtuple 関数に、カラーコードを表す Color という名前と、3つのフィールド名 redgreenblue を指定しています。これにより、Color タプルは、次のように作成できます。

c = Color(255, 0, 0)

この例では、Color タプルの red フィールドには 255green フィールドには 0blue フィールドには 0 が格納されます。これらのフィールドには、通常のタプルと同様に、インデックス番号を使ってアクセスすることができます。

print(c[0]) # 255
print(c[1]) # 0
print(c[2]) # 0

また、namedtuple によって生成されるクラスには、_fields 属性があります。これは、フィールド名のリストを格納しています。

print(Color._fields) # ('red', 'green', 'blue')

namedtuple を使うことで、タプルの要素に名前をつけることができるため、可読性が向上するという利点があります。また、namedtuple は、通常のタプルと同様に軽量で、処理速度が速いため、タプルを使用する場合に、より分かりやすく安全なコードを書くことができます。

collections.OrderedDictとPython3.6のdict

collections.OrderedDict は、Pythonのデータ型の1つで、キー-値ペアを保持するディクショナリで、要素の順序が追加された順序で保持される点が、通常のディクショナリ (dict) と異なります。collections モジュールをインポートして使用します。

dict はPythonの標準ライブラリに含まれるデータ型で、キー-値ペアを保持するために使用されます。通常の dict は、キーの順序を保証していません。これは、要素を追加した順序とは異なる順序でイテレーションするため、多くの場合、要素の順序が重要でない場合には問題になりません。

一方、collections.OrderedDict は、要素が追加された順序で保持されるため、要素の順序が重要な場合に使用されます。以下は、OrderedDict を使用して、要素の順序を保持するディクショナリを作成する例です。

from collections import OrderedDict

# 要素の追加順序が保持される辞書を作成する
d = OrderedDict()
d['one'] = 1
d['two'] = 2
d['three'] = 3

print(d) # OrderedDict([('one', 1), ('two', 2), ('three', 3)])

この例では、OrderedDict クラスをインスタンス化して d という名前の変数に代入し、3つの要素を追加しています。ディクショナリ d を出力すると、要素の追加順序が保持されていることがわかります。

通常の dict との違いは、次のようにイテレーションした場合にもわかります。

# 通常の辞書を作成する
d = {'one': 1, 'two': 2, 'three': 3}

# 通常の辞書をイテレーションする
for k, v in d.items():
print(k, v)
# 要素の追加順序が保持される辞書をイテレーションする
for k, v in OrderedDict(d).items():
print(k, v)

この例では、OrderedDict クラスをインスタンス化して d という名前の変数に代入し、3つの要素を追加しています。ディクショナリ d を出力すると、要素の追加順序が保持されていることがわかります。

通常の dict との違いは、次のようにイテレーションした場合にもわかります。

# 通常の辞書を作成する
d = {'one': 1, 'two': 2, 'three': 3}

# 通常の辞書をイテレーションする
for k, v in d.items():
print(k, v)
# 要素の追加順序が保持される辞書をイテレーションする
for k, v in OrderedDict(d).items():
print(k, v)

この例では、まず通常の dict をイテレーションして kv を出力しています。次に、OrderedDict を使用して d を変換してからイテレーションし、kv を出力しています。

正規表現 re

正規表現(regular expression)は、文字列のパターンを記述するための表現方法です。正規表現を使うことで、文字列のパターンを簡単に検索したり、置換したりすることができます。Pythonでは、reモジュールを使って正規表現を処理することができます。

reモジュールには、正規表現を処理するための多くの関数が用意されています。主な関数としては、以下のものがあります。

  • re.search(pattern, string)
    • 指定された正規表現パターンを、文字列内で検索します。最初にマッチした箇所を返します。マッチしなかった場合はNoneを返します。
  • re.match(pattern, string)
    • 指定された正規表現パターンを、文字列の先頭から検索します。最初にマッチした箇所を返します。マッチしなかった場合はNoneを返します。
  • re.findall(pattern, string)
    • 指定された正規表現パターンにマッチする部分文字列を、文字列内からすべて検索します。結果はリストとして返されます。
  • re.sub(pattern, repl, string)
    • 指定された正規表現パターンにマッチする部分文字列を、置換文字列replで置換します。結果の文字列が返されます。

正規表現パターンは、文字列内で検索するパターンを表します。パターンは、特定の文字列や文字クラス、任意の文字列、または文字列の繰り返し等を指定することができます。以下は、正規表現パターンの一例です。

  • .: 任意の1文字にマッチします。
  • []: 指定された文字集合にマッチします。例えば、[abc]ab、またはcにマッチします。
  • ^: 行の先頭にマッチします。^abcは、abcで始まる行にマッチします。
  • $: 行の末尾にマッチします。abc$は、abcで終わる行にマッチします。
  • *: 直前の文字が0回以上繰り返されることにマッチします。
  • +: 直前の文字が1回以上繰り返されることにマッチします。
  • ?: 直前の文字が0回または1回出現することにマッチします。
  • |: |で区切られたいずれかのパターンにマッチします。
  • (): パターンをグループ化し、キャプチャします。グループ化されたパターンにマッチした部分文字列は、マッチオブジェクトからグループ番号で取得することができます。

例えば、re.search('a.*c', 'abcde')は、文字列'abcde'の中で最初にaで始まりcで終わる部分文字列を検索します。この場合、マッチする文字列は'abc'です。

正規表現パターンをより複雑にする場合、複数の行にまたがるパターンを指定する必要がある場合など、パターン文字列が長くなってしまうことがあります。そのような場合には、re.compile関数を使ってパターンをコンパイルし、再利用可能な正規表現オブジェクトを作成することができます。

また、正規表現パターンを読みやすくするために、re.VERBOSEオプションを使ってパターン文字列を複数行に分けたり、コメントを挿入したりすることができます。re.VERBOSEオプションを指定する場合は、パターン文字列をトリプルクオートで囲んで複数行にわたって記述します。以下は、re.VERBOSEオプションを使った正規表現パターンの例です。

import re

pattern = re.compile(r'''
^ # 行頭
[A-Za-z0-9_-]+ # ユーザー名
@ # @記号
[A-Za-z0-9_-]+ # ドメイン名
\. # .記号
[A-Za-z]{2,4} # トップレベルドメイン
$ # 行末
''', re.VERBOSE)
email = 'example123@example.com'
if pattern.match(email):
print('Valid email address')
else:
print('Invalid email address')

この例では、re.compile関数を使って、複数行にわたる正規表現パターンをコンパイルしています。re.VERBOSEオプションを指定しているため、パターン文字列を複数行に分け、コメントを挿入することができます。match関数を使って、email変数の文字列が正規表現パターンにマッチするかどうかを判定しています。

正規表現のre.groupとre.compileとre.VERBOSE

re.groupre.compile、およびre.VERBOSEについて説明します。

re.groupは、正規表現パターンによるマッチング結果から、マッチした部分文字列を取り出すためのメソッドです。正規表現パターン内にグループ化されたパターンがある場合、re.groupを使って、それぞれのグループに対応するマッチ結果を取り出すことができます。グループ番号は、()でグループ化したパターンの左から数えて、最初のグループが1、2番目のグループが2、というように順に割り振られます。以下は、re.groupメソッドの例です。

import re

pattern = re.compile(r'(\d{4})-(\d{2})-(\d{2})') # YYYY-MM-DD形式の日付をマッチさせるパターン
date_str = '2022-02-16'
match_obj = pattern.match(date_str)
if match_obj:
year = match_obj.group(1)
month = match_obj.group(2)
day = match_obj.group(3)
print(f'year: {year}, month: {month}, day: {day}')
else:
print('No match')

この例では、re.compile関数を使って正規表現パターンをコンパイルし、matchメソッドで文字列をマッチングしています。マッチングに成功した場合、re.groupメソッドを使って、日付文字列から年月日を取り出しています。

re.compileは、正規表現パターンをコンパイルして再利用可能な正規表現オブジェクトを作成するための関数です。re.compileを使うと、同じ正規表現パターンを何度も再利用する場合に効率的に処理することができます。以下は、re.compile関数を使った例です。

import re

pattern = re.compile(r'\d{4}-\d{2}-\d{2}') # YYYY-MM-DD形式の日付をマッチさせるパターン
date_str = '2022-02-16'
if pattern.match(date_str):
print('Match')
else:
print('No match')
date_str2 = '2022-02-16'
if pattern.match(date_str2):
print('Match')
else:
print('No match')

この例では、同じ正規表現パターンを2回使って、それぞれ異なる文字列をマッチングしています。re.compile関数を使うことで、正規表現パターンを事前にコンパイルしておき、再利用可能な正規表現オブジェクトを作成しています。そのため、2回目のマッチングでは、正規表現パターンを再コンパイルする必要がありません。

re.VERBOSEは、正規表現パターンをより読みやすく、分かりやすくするために使われます。正規表現パターンはしばしば複雑で、視覚的に理解するのが難しいことがあります。re.VERBOSEを使うと、正規表現パターンを複数行に分け、コメントを付けることができます。以下は、re.VERBOSEを使った例です。

この例では、re.VERBOSEフラグを使って、日付と時刻の正規表現パターンを複数行に分けて書いています。また、コメントも付けています。re.VERBOSEを使うことで、正規表現パターンをより読みやすく、分かりやすくすることができます。

正規表現のre.splitの分割とre.compileの置換

正規表現の re.split() メソッドは、指定した正規表現パターンによって文字列を分割することができます。re.split() メソッドの使い方は以下の通りです。

import re

pattern = r'[._-]' # 区切り文字はピリオド、アンダースコア、ハイフン
string = 'spam_egg-ham.bar'
result = re.split(pattern, string)
print(result) # ['spam', 'egg', 'ham', 'bar']
import re
pattern = r'[._-]' # 区切り文字はピリオド、アンダースコア、ハイフン
string = 'spam_egg-ham.bar'
result = re.split(pattern, string)
print(result) # ['spam', 'egg', 'ham', 'bar']

上記の例では、文字列をピリオド、アンダースコア、ハイフンのどれかで分割しています。

正規表現の re.compile() メソッドは、指定した正規表現パターンをコンパイルして正規表現オブジェクトを作成します。正規表現オブジェクトは、search()match() などのメソッドを持っており、これらを使って文字列を検索することができます。

また、正規表現オブジェクトには sub() メソッドがあり、このメソッドを使うと文字列の中から正規表現パターンにマッチした部分を別の文字列に置換することができます。re.sub() メソッドと同様に、sub() メソッドも re.compile() メソッドを使って正規表現オブジェクトを作成することができます。以下は、正規表現オブジェクトを使った置換の例です。

import re
pattern = re.compile(r'(?P<name>\w+)\s(?P<age>\d+)') # 名前と年齢のパターン
string = 'Alice 25, Bob 30, Charlie 35'

result = pattern.sub(r'\g<age> - \g<name>', string)
print(result) # 25 - Alice, 30 - Bob, 35 - Charlie

上記の例では、re.compile() メソッドを使って正規表現オブジェクトを作成し、sub() メソッドで文字列を置換しています。正規表現パターン (?P<name>\w+)\s(?P<age>\d+) は、名前と年齢のパターンを表しています。sub() メソッドの第一引数には、置換後の文字列の書式を指定しています。\g<age>\g<name> は、それぞれ名前と年齢のグループにマッチした文字列を指します。

正規表現のGreedy

正規表現の Greedy とは、一般的に「貪欲」と訳されます。Greedy は、正規表現において量指定子を使った時のデフォルトの動作を表しています。

例えば、以下のような正規表現を考えてみましょう。

import re
pattern = r'<.*>'
string = '<html><head><title>Title</title></head><body>Body</body></html>'
result = re.search(pattern, string)
print(result.group(0)) # <html><head><title>Title</title></head><body>Body</body></html>

上記の例では、<.*> という正規表現パターンを使って、文字列から <> で囲まれた部分を抜き出しています。* は直前の文字が0回以上繰り返されることを表しており、.* は任意の文字が0回以上繰り返されることを表しています。

この正規表現を実行すると、Greedy な挙動により最初の < から最後の > までを一つのマッチとして扱い、全体が抜き出されます。このように、Greedy は最長のマッチを優先するため、マッチ結果が予想と異なる場合があります。

Greedy を避ける方法として、量指定子の後に ? を付けることで、Non-Greedy なマッチを行うことができます。以下は、Non-Greedy なマッチを行う例です。

import re
pattern = r'<.*?>'
string = '<html><head><title>Title</title></head><body>Body</body></html>'
/* Your code... */

result = re.search(pattern, string)
print(result.group(0)) # <html>

上記の例では、<.*?> という正規表現パターンを使って、最短のマッチを行っています。*? は、直前の文字が0回以上繰り返されることを表しており、.*? は任意の文字が0回以上繰り返され、最短のマッチが行われることを表しています。このように、Non-Greedy なマッチを使うことで、マッチ結果を正確に取得することができます。

format表記

format メソッドは、文字列に変数の値を埋め込んで生成する際に使用することができます。Python では、文字列の中に {} といった特殊な文字列を書いておき、format メソッドに引数として渡すことで、引数の値を文字列に埋め込むことができます。

例えば、以下のようなコードを考えてみましょう。

x = 1
y = 2
z = 3
s = "x = {}, y = {}, z = {}".format(x, y, z)
print(s)

上記のコードでは、format メソッドを使って、変数 xyz の値を文字列に埋め込んでいます。{} の中には、埋め込む変数のインデックスを指定することができます。デフォルトでは、インデックスは0から順に振られますが、{n} のようにしてインデックスを指定することもできます。

また、Python 3.6 からは、f文字列 (f-strings) という便利な表記方法が追加されました。f文字列は、文字列の先頭に f を付けることで使うことができます。f文字列では、文字列内に変数名をそのまま書くことができ、Python が自動的に変数の値を埋め込んでくれます。

例えば、上記のコードをf文字列を使って書くと以下のようになります。

x = 1
y = 2
z = 3
s = f"x = {x}, y = {y}, z = {z}"
print(s)

f文字列を使うことで、より簡潔なコードを書くことができます。ただし、f文字列はPython 3.6以降でしか使えないため、Python 2.x や Python 3.5 以下のバージョンを使っている場合は、代替の方法を使う必要があります。

repairとstr

str はPythonにおける基本データ型の一つで、文字列を表現するために使われます。一方、replace メソッドは、文字列の中の特定の文字列を、別の文字列に置き換えるために使われます。replace メソッドは、文字列を不変オブジェクトとして扱うPythonにおいて、新しい文字列を生成するために使われます。

replace メソッドは、以下のように使います。

s = "Hello, world!"
s = s.replace("world", "Python")
print(s) # "Hello, Python!"

上記のコードでは、replace メソッドを使って、文字列sの中の "world""Python" に置き換えています。ただし、文字列s自体は不変オブジェクトであるため、replace メソッドを呼び出した結果として得られる新しい文字列がsに代入されています。

一方、str データ型自体を変更するには、文字列のスライスを用いて部分文字列を置き換える必要があります。例えば、以下のように書くことができます。

s = "Hello, world!"
s = s[:7] + "Python!"
print(s) # "Hello, Python!"

上記のコードでは、スライスを使って、文字列sの最初の7文字 ("Hello, ") と "world!" の代わりに "Python!" を代入しています。このように、文字列自体を変更するためには、スライスを使って部分文字列を置き換える必要があります。

pprint vs json.dumps

pprintjson.dumps は、どちらもPythonのオブジェクトを文字列に変換するために使われますが、それぞれ異なる使い方があります。

pprint は、Pythonのオブジェクトを見やすい形式で出力するために使われます。特に、入れ子になったデータ構造を表示する場合に便利です。例えば、以下のように使うことができます。

import pprint

data = {
"name": "John Smith",
"age": 42,
"languages": ["Python", "JavaScript", "Java", "C++"],
"address": {
"city": "New York",
"state": "NY",
"zip": "10001"
}
}
pprint.pprint(data)

上記のコードでは、Pythonの辞書型を定義しています。その後、pprint.pprint 関数を使って、これを見やすい形式で出力しています。出力結果は以下のようになります。

{'address': {'city': 'New York', 'state': 'NY', 'zip': '10001'},
'age': 42,
'languages': ['Python', 'JavaScript', 'Java', 'C++'],
'name': 'John Smith'}

一方、json.dumps は、PythonのオブジェクトをJSON形式の文字列に変換するために使われます。JSON形式は、JavaScript Object Notationの略で、データを表現するための軽量なフォーマットです。例えば、以下のように使うことができます。

import json
data = {
"name": "John Smith",
"age": 42,
"languages": ["Python", "JavaScript", "Java", "C++"],
"address": {
"city": "New York",
"state": "NY",
"zip": "10001"
}
}
json_string = json.dumps(data)

print(json_string)

上記のコードでは、Pythonの辞書型を定義しています。その後、json.dumps 関数を使って、これをJSON形式の文字列に変換しています。出力結果は以下のようになります。

{"name": "John Smith", "age": 42, "languages": ["Python", "JavaScript", "Java", "C++"], "address": {"city": "New York", "state": "NY", "zip": "10001"}}

pprintjson.dumps は、それぞれ異なる目的で使われるため、使い分ける必要があります。pprint は主にデバッグや可読性のために使われ、json.dumps は主にデータのシリアライズやデータのやり取りのために使われます。

ビット演算

ビット演算は、2進数で表された数値の各ビットを操作する演算です。ビット演算には、以下のような演算子があります。

  • ビット単位の論理積 (&)
  • ビット単位の論理和 (|)
  • ビット単位の排他的論理和 (^)
  • ビット単位の反転 (~)
  • 左シフト (<<)
  • 右シフト (>>)

これらの演算子を使うことで、ビット演算を行うことができます。

例えば、以下のように使うことができます。

a = 0b1010 # 10
b = 0b1100 # 12
# ビット単位の論理積
c = a & b # 0b1000 (8)

# ビット単位の論理和
d = a | b # 0b1110 (14)
# ビット単位の排他的論理和
e = a ^ b # 0b0110 (6)
# ビット単位の反転 
f = ~a # -11 (0b...11110101)
# 左シフト
g = a << 2 # 0b101000 (40)
# 右シフト
h = b >> 2 # 0b0011 (3)

ビット演算は、2進数で表された数値の各ビットを操作する演算です。ビット演算には、以下のような演算子があります。

  • ビット単位の論理積 (&)
  • ビット単位の論理和 (|)
  • ビット単位の排他的論理和 (^)
  • ビット単位の反転 (~)
  • 左シフト (<<)
  • 右シフト (>>)

これらの演算子を使うことで、ビット演算を行うことができます。

例えば、以下のように使うことができます。

python
a = 0b1010 # 10
b = 0b1100 # 12

# ビット単位の論理積
c = a & b # 0b1000 (8)

# ビット単位の論理和
d = a | b # 0b1110 (14)

# ビット単位の排他的論理和
e = a ^ b # 0b0110 (6)

# ビット単位の反転
f = ~a # -11 (0b...11110101)

# 左シフト
g = a << 2 # 0b101000 (40)

# 右シフト
h = b >> 2 # 0b0011 (3)

上記の例では、ab という2進数で表された数値を定義しています。その後、ビット演算子を使って、論理積、論理和、排他的論理和、反転、左シフト、右シフトの演算を行っています。

ビット演算は、主にシステムプログラムやデバイスドライバ、ネットワークプログラムなど、低レベルのプログラミングで使用されます。また、ビット演算を駆使することで、アルゴリズムの効率化なども図ることができます。

Enum

Enumとは、列挙型を表すクラスであり、列挙子を定義して、列挙値を表現します。Python 3.4以降では、標準ライブラリの enum モジュールが提供されており、Enumを使うことができます。

Enumを定義するには、Enum クラスを継承し、各列挙子を定義します。各列挙子は、通常、大文字で定義されます。また、列挙子には、値を割り当てることもできます。以下は、Enumの例です。

from enum import Enum

class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

上記の例では、Color というEnumを定義しています。Enumの要素として、REDGREENBLUE の列挙子があり、それぞれ 123 の値を持っています。

このEnumは、以下のように使うことができます。

print(Color.RED) # Color.RED
print(Color.RED.value) # 1
print(Color.GREEN) # Color.GREEN
print(Color.GREEN.value) # 2
print(Color.BLUE) # Color.BLUE
print(Color.BLUE.value) # 3
if Color.RED == Color.GREEN:
print("同じ色です")
else:
print("異なる色です") # 異なる色です

また、Enumには、継承している Enum クラスのメソッドや属性があります。例えば、 name プロパティを使って、列挙子の名前を取得することができます。以下は、name プロパティを使った例です。

print(Color.RED.name) # RED
print(Color.GREEN.name) # GREEN
print(Color.BLUE.name) # BLUE

列挙子に割り当てた値が重複してしまうと、 ValueError が発生します。また、列挙子に割り当てた値が必要ない場合、Enumの要素として、以下のように定義することもできます。

class Size(Enum):
SMALL = 1
MEDIUM = 2
LARGE = 3

このように、Enumを使うことで、プログラム内で定数を扱うことが容易になります。また、Enumの要素には、対応する値を割り当てることができるため、複数の値を持つ要素を定義することもできます。

functools.Iru_cacheとmemoize

functools.lru_cache とは、関数の戻り値をキャッシュするデコレータです。引数をキーとして、関数の結果を保持しておくため、同じ引数で呼び出された場合はキャッシュから返すことができます。LRU(Least Recently Used)というアルゴリズムを用いて、キャッシュサイズを制限することもできます。

functools.lru_cache は、以下のように定義されます。

functools.lru_cache(maxsize=128, typed=False)

functools.lru_cache とは、関数の戻り値をキャッシュするデコレータです。引数をキーとして、関数の結果を保持しておくため、同じ引数で呼び出された場合はキャッシュから返すことができます。LRU(Least Recently Used)というアルゴリズムを用いて、キャッシュサイズを制限することもできます。

functools.lru_cache は、以下のように定義されます。

python
functools.lru_cache(maxsize=128, typed=False)

maxsize は、キャッシュのサイズを指定する引数であり、 typed は、引数の型を区別するかどうかを指定する引数です。

また、memoize は、Python 2.x で利用されていたデコレータで、 functools.lru_cache のように関数の戻り値をキャッシュするためのデコレータです。以下は、memoize の実装例です。

import functools
def memoize(function):
cache = {}
@functools.wraps(function)
def wrapper(*args):
if args in cache:
return cache[args]
else:
result = function(*args)
cache[args] = result
return result
return wrapper

この memoize デコレータは、関数の引数をキーとして、関数の戻り値を cache に保存します。また、キーが既にキャッシュに存在する場合は、キャッシュから値を返します。

memoize デコレータは、functools.lru_cache よりも簡単な実装であり、キャッシュのサイズ制限や、引数の型の区別はできませんが、基本的な動作は同じです。ただし、Python 3.x では、 functools.lru_cache が提供されているため、 memoize を使うことは推奨されません。

functools.wraps

functools.wraps は、デコレータを使って関数を修飾した際に、元の関数の情報を保持するためのデコレータです。デコレータを使って関数を修飾すると、関数名や引数、ドキュメンテーション文字列など、元の関数に関する情報が失われることがあります。そのような情報が欠落すると、デバッグやドキュメンテーションの作成が困難になります。

functools.wraps デコレータは、以下のように定義されます。

def wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES):
return functools.partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)

wraps は、 update_wrapper 関数に wrapped 引数を渡して、デコレートされた関数に元の関数の情報を割り当てます。assigned 引数は、コピーされる属性のリストであり、 updated 引数は、上書きされる属性のリストです。デフォルトでは、 assigned には __module__, __name__, __qualname__, __doc__ の4つの属性が、 updated には __dict__ のみが設定されています。

以下は、 functools.wraps を使ったデコレータの例です。

import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Before the function is called.")
result = func(*args, **kwargs)
print("After the function is called.")
return result
return wrapper
@my_decorator
def example_function():
"""This is an example function."""
print("The example function is called.")

この例では、 my_decorator デコレータを使って example_function を修飾しています。デコレータは、wrapper 関数を返し、wrapper 関数の中で example_function を呼び出しています。 functools.wraps デコレータがなければ、 example_function のドキュメンテーション文字列が失われてしまいますが、 wraps デコレータがあるため、 example_function のドキュメンテーション文字列が保持されます。

functools.partial

functools.partial 関数は、ある関数に一部の引数を事前に設定して新しい関数を作成するための関数です。partial 関数は、特定の関数とその一部の引数を取り、新しい関数を返します。新しい関数は、元の関数に対して、設定された引数が与えられた引数として使用されます。

partial 関数は、以下のように定義されます。

functools.partial(func, /, *args, **keywords)

func は元の関数、*args は元の関数に与える引数、 **keywords は元の関数に与えるキーワード引数です。partial で作成された新しい関数を呼び出すと、設定された引数と呼び出し時に与えられた引数が元の関数に渡されます。

以下は、 functools.partial を使用した例です。

import functools
def greeting(name, greeting_word):
return f"{greeting_word}, {name}!"
say_hello = functools.partial(greeting, greeting_word="Hello")
say_hi = functools.partial(greeting, greeting_word="Hi")
print(say_hello("Alice"))
print(say_hello("Bob"))
print(say_hi("Charlie"))
print(say_hi("David"))

この例では、 greeting 関数に name 引数を渡す前に greeting_word 引数を設定するために、 partial を使用して2つの新しい関数 say_hellosay_hi を作成しています。say_hellosay_hi 関数は、 greeting 関数に name 引数を与える必要がありますが、 greeting_word 引数はあらかじめ設定されています。これにより、 say_hello 関数を "Hello" という挨拶文で呼び出すと、 "Hello, Alice!""Hello, Bob!" といった出力が得られます。同様に、 say_hi 関数を "Hi" という挨拶文で呼び出すと、 "Hi, Charlie!""Hi, David!" といった出力が得られます。


というわけで、今回は以上です。大変大変お疲れ様でした。
引き続きで、徐々に発信していきます。

コメントや感想を受け付けています。ちょっとした感想でもいいので嬉しいです。

それでは、以上です。

【ステップアップ】「Pythonの実践」簡単速習‼【グラフィックス/応用⑨】

最新情報をチェックしよう!