こんにちはヤク学長です。
データサイエンティスト兼ファーマシストで、アルゴリズムやBI開発を行っています。
本記事の目的は、「pythonの基本操作を知る」ことを目的としています。
【本記事のもくじ】
まず、「Python」に真剣に取り組むための概要を解説します。
下記の方法で、簡単に概要を抑えることができます。
- 1.Pythonの便利ツール
それでは、上から順番に見ていきます。
なお、本上記の方法を順番に抑えれば成果が出ます。
記事の内容は「転載 & 引用OK」問題ありません。
- 1 1.Pythonの便利ツール
- 1.1 IPython
- 1.2 contexlib.contexmanager
- 1.3 contexlib.conte
- 1.4 contextmanager
- 1.5 contexlib.ContexDecorater
- 1.6 contexlib.suppress
- 1.7 contexlib.redirect_stdoutとcontexlib.redict_sterr
- 1.8 contexlib.ExitStack
- 1.9 ioストリーム
- 1.10 collections.ChinMap
- 1.11 collections.dafaultdict
- 1.12 collections.Counter
- 1.13 collections.deque
- 1.14 collections.namedtuple
- 1.15 collections.OrderedDictとPython3.6のdict
- 1.16 正規表現 re
- 1.17 正規表現のre.groupとre.compileとre.VERBOSE
- 1.18 正規表現のre.splitの分割とre.compileの置換
- 1.19 正規表現のGreedy
- 1.20 format表記
- 1.21 repairとstr
- 1.22 pprint vs json.dumps
- 1.23 ビット演算
- 1.24 Enum
- 1.25 functools.Iru_cacheとmemoize
- 1.26 functools.wraps
- 1.27 functools.partial
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
contextmanager
はcontextlib
モジュールにあるデコレータで、クラスを定義することなく、簡単にコンテキストマネージャーを作成することができます。
以下は、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_context
とExit 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_stdout
と redirect_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
は、 dict1
と dict2
を連結したものです。 chain_map
は、まず dict1
を検索し、その次に dict2
を検索します。つまり、 b
の値は dict1
によって 2
に設定され、これで、 chain_map
は、 dict1
と dict2
を連結したものです。 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
は、 dict1
、 dict2
、 dict3
を順番に検索します。つまり、 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'])
出力結果は以下の通りになります。
3
また、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つのフィールド名 red
、green
、blue
を指定しています。これにより、Color
タプルは、次のように作成できます。
c = Color(255, 0, 0)
この例では、Color
タプルの red
フィールドには 255
、green
フィールドには 0
、blue
フィールドには 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
をイテレーションして k
と v
を出力しています。次に、OrderedDict
を使用して d
を変換してからイテレーションし、k
と v
を出力しています。
正規表現 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]
はa
、b
、または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.group
、re.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
メソッドを使って、変数 x
、y
、z
の値を文字列に埋め込んでいます。{}
の中には、埋め込む変数のインデックスを指定することができます。デフォルトでは、インデックスは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
pprint
と json.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"}}
pprint
と json.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進数で表された数値の各ビットを操作する演算です。ビット演算には、以下のような演算子があります。
- ビット単位の論理積 (&)
- ビット単位の論理和 (|)
- ビット単位の排他的論理和 (^)
- ビット単位の反転 (~)
- 左シフト (<<)
- 右シフト (>>)
これらの演算子を使うことで、ビット演算を行うことができます。
例えば、以下のように使うことができます。
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)
上記の例では、a
と b
という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の要素として、RED
、GREEN
、BLUE
の列挙子があり、それぞれ 1
、2
、3
の値を持っています。
この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
は、以下のように定義されます。
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_hello
と say_hi
を作成しています。say_hello
と say_hi
関数は、 greeting
関数に name
引数を与える必要がありますが、 greeting_word
引数はあらかじめ設定されています。これにより、 say_hello
関数を "Hello"
という挨拶文で呼び出すと、 "Hello, Alice!"
や "Hello, Bob!"
といった出力が得られます。同様に、 say_hi
関数を "Hi"
という挨拶文で呼び出すと、 "Hi, Charlie!"
や "Hi, David!"
といった出力が得られます。
というわけで、今回は以上です。大変大変お疲れ様でした。
引き続きで、徐々に発信していきます。
コメントや感想を受け付けています。ちょっとした感想でもいいので嬉しいです。
それでは、以上です。