5.1 組み込み関数とモジュール

(1/1)
関数のイメージ
Python では、平方根や三角関数のような数学関数のほか、キーボードからデータ入力したり画面にデータ出力する機能も関数として、あらかじめ用意されている。また、import文でモジュールを取り込むことで、カレンダー計算やホームページ解析をするための便利な関数を利用できるようになる。さらに、インターネット上には pipコマンドを使ってインストールすると利用できるようになる多くの便利な外部ライブラリが公開されている。

目次

サンプル・プログラム

関数とは

2次関数のグラフ
一次関数、二次関数、対数関数、三角関数‥‥数学で関数と言えば、\( y = f(x) \) と表し、\( x \) の値が決まれば、\( y \) の値が1つに決まる関係を意味する。
Python を含む多くのプログラミング言語には関数という仕組みが用意されており、\( x \) のことを引数 (ひきすう) 、\( y \) のことを戻り値 (もどりち) と呼ぶ。関数によっては引数を複数指定する場合もあるし、1つも指定しない場合もある。戻り値は1つだが、Pythonではリストのように1つの戻り値の中に複数の値を記入することができる。
ただし、数学の関数の定義どおり、同じ引数に対しては必ず同じ戻り値が返る(リストの中身も同じ)

プログラミング言語における関数は、数学の関数と同じように戻り値を計算して返すものだけでなく、キーボードからデータ入力したり、画面にデータを表示したり、ファイル入出力したり、クラウドと連携するような作用を持つものがある。

組み込み関数

これまで何度か見てきたように、Python にはあらかじめ多くの関数が用意されており、これを組み込み関数と呼ぶ。ここで一覧表に整理しておこう。たくさんあるように見えるが、本シリーズで扱うのは、この一覧表のほんの一部である。
Pythonの組み込み関数一覧
関数戻り値・作用
abs絶対値を返す。
aiter非同期イテレーションが可能なオブジェクトのイテレーターを返す。
allイテラブルオブジェクトの要素がすべて真かどうかを返す。
anext非同期イテレータから次の値を返す。
any要素が1つでも真ならTrueを返す。
ascii与えられた文字列をASCIIコードに変換して返す。
bin与えられた整数を2進数表記の文字列として返す。
bool引数の真偽を判定する。
breakpointデバッグモードに入る。Python 3.7で追加された。
bytearrayデータをバイト列に変換して返す。
bytesbytearrayのイミュータブル版。
callable呼び出し可能オブジェクトであればTrueを返す。
chr与えられた数値をコードとするUnicode文字を返す。
classmethodメソッドをクラスメソッドへ変換する。
compile与えられたPythonコードを内部表現にコンパイルする。
complex与えられた実部と虚部から複素数を返す。
delattr指定したオブジェクトから属性を削除する。
dict辞書を作成する。
dir与えられたオブジェクトの有効な属性リストを返す。
divmod商と剰余を返す。
enumerateenumerateオブジェクトを返す。
eval与えられた文字列をPythonコードとして実行する。
exec与えられた文字列を文として実行する。
filter条件を満たす要素を抽出して返す。
float与えられた文字列を浮動小数に変換して返す。
format文字列の書式を整える。
frozensetfrozensetオブジェクトを返す。
getattr属性の値を返す。
globalsグローバルスコープに定義されている関数や変数を返す。
hasattr属性を持っているかどうかを返す。
hashハッシュ値を返す。
helpヘルプシステムを起動する。
hex与えられた整数を16進数表記の文字列として返す。
idオブジェクトのIDを返す。
inputキーボードから入力した文字列を返す。
int与えられた文字列を整数に変換して返す。
isinstance指定した型またはサブクラスのインスタンスである場合にTrueを返す。
issubclass指定したクラスまたはサブクラスである場合にTrueを返す。
iteriteratorオブジェクトを返す。
lenオブジェクトの長さ(要素の数)を返す。
listリストを作成する。
localsローカルスコープに定義されている関数や変数を返す。
mapシーケンスの構成要素すべてに対して指定した処理を行う。
max与えられた要素の中の最大値を返す。
memoryviewmemoryviewオブジェクトを取得する。
min与えられた要素の中の最小値を返す。
nextイテレータの次の要素を返す。
objectオブジェクトを返す。
oct与えられた整数を8進数表記の文字列として返す。
openファイルをオープンする。
ord与えられた文字のUnicodeコード(整数)を返す。
powべき乗を返す。
print画面に表示する。
propertyproperty属性を返す。
rangerangeオブジェクトを返す。
repr与えられたオブジェクトの文字列表現を返す。
reversed要素を逆順に並べ替える。
round数値を丸めて返す。
setsetオブジェクトを返す。
setattrオブジェクトに属性を追加する。
slice要素の一部を返す。
sorted要素を並べ替えて返す。
staticmethodメソッドを静的メソッドへ変換する。
str与えられたオブジェクトを文字列に変換して返す。
sum要素の合計を返す。
superスーパークラス(親クラス)に関するオブジェクトを返す。
tupleタプルを作成する。
type与えられたオブジェクトの型を返す。
varsクラス内に保持している情報を返す。
zip要素をまとめて返す。
__import__ import文により呼び出される関数。
ここで組み込み関数 divmod を使ったサンプル・プログラム "divmod.py" を作ってみた。除数と被除数を入力すると、divmod を使って商と余りを表示する簡単なプログラムだ。
divmod.py
# メイン・プログラム =======================================================
# キーボードから入力する(文字列).
aStr  = input("除数=")
bStr  = input("被除数=")

# 入力バリデーション(数字(文字列)→数値変換)
try:
	a = validateNumber(aStr, "int", INPUT_NUMBER_MIN, INPUT_NUMBER_MAX, "除数")
	b = validateNumber(bStr, "int", INPUT_NUMBER_MIN, INPUT_NUMBER_MAX, "被除数")

# 失敗したらエラーメッセージを表示してプログラムを終了する.
except ValueError as e:
	dispErrorMessageAndExit(str(e))

# 商と剰余を求める
(div, mod) = divmod(a, b)

# 画面に表示する.
print(f"{a}÷{b}={div}...{mod}")
(div, mod) = divmod(a, b) のうち、a と b が引数で、(div, mod) が戻り値

モジュール

これまで何度か見てきたように、Python には多くの標準ライブラリ外部ライブラリがモジュールとして用意されている。たとえば三角関数を使いたいときは、標準ライブラリ mathimport して、math.sin() のようにして使う。
モジュールによって容易に機能拡張できるのが Python の特長で、このことにより、多くの利用者に受け入れられ、多くの業種で活用されている。
ここでは、標準ライブラリでよく使うものを一覧表に整理しておく。
Pythonの標準ライブラリでよく使うもの
標準ライブラリ内 容
math数学関数
decimal10進数算術演算
fractions有理数(分数を含む)
random疑似乱数
statistics数学的統計関数
datetime日付や時刻(基本)
dateutil日付や時刻
calendarカレンダー計算
string文字列操作
re正規表現
jsonJSONエンコーダーとデコーダー
base64Base16, Base32, Base64, Base85データのエンコード
htmlHTMLデータ処理
xmlXMLデータ処理
webbrowser便利なウェブブラウザコントローラー
httpHTTP通信
sqlite3SQLiteデータベースへのインターフェース
csvCSV形式ファイル読み書き
zlibgzip互換の圧縮
gzipgzipファイルのサポート
sys実行環境に関わるライブラリ
osOSに依存した機能を使うためのライブラリ
atexit終了ハンドラ
argparseコマンラインオプションの解釈
threadingスレッドベースの並列処理
multiprocessingプロセスベースの並列処理
asyncio非同期I/O
socket低水準ネットワークインターフェース
sslソケットオブジェクト用のTLS/SSL ラッパー
email電子メールと MIME 処理のためのパッケージ
標準ライブラリ calendar を使って1ヶ月分の万年カレンダーを表示するプログラムが "monthCalendar.py" である。このように、標準ライブラリを活用することで、簡単に目的のプログラムを書くことができる。
monthCalendar.py
# メイン・プログラム =======================================================
# キーボードから入力する(文字列).
yearStr  = input("西暦年=")
monthStr = input("月=")

# 入力バリデーション(数字(文字列)→数値変換)
try:
	year = validateNumber(yearStr, "int", INPUT_YEAR_MIN, INPUT_YEAR_MAX, "西暦年")
	month = validateNumber(monthStr, "int", INPUT_MONTH_MIN, INPUT_MONTH_MAX, "月")

# 失敗したらエラーメッセージを表示してプログラムを終了する.
except ValueError as e:
	dispErrorMessageAndExit(str(e))

# カレンダーを作成する.
cal = calendar.TextCalendar(calendar.SUNDAY)
monthCalendar = cal.formatmonth(year, month)

#画面に表示する.
print(monthCalendar)
次に外部ラリブラリを使ってみよう。
外部ライブラリ BeautifulSouprequests を使って、指定したサイトの の内容を表示するプログラムが "getHtmlTags1.py" である。
外部ラリブラリを使うときは、まず、pipコマンドを使って外部ライブラリを実行環境にインストールする。
pip install beautifulsoup4
pip install requests
Python には多くの外部ライブラリが出回っており、ネットを検索することで、目的のプログラムを簡単に書けるような外部ライブラリが見つかるだろう。
ただし、外部ライブラリを使うプログラムは、実行環境にも外部ライブラリをインストールする必要があるので、配布時に注意が必要である。
getHtmlTags1.py
# メイン・プログラム =======================================================
# モジュールをimportする.
try:
	import requests
	from bs4 import BeautifulSoup
except ImportError as e:
	print(f"外部ライブラリをインストールしてください ... {e}")
else:
	response = requests.get(TARGET_URL)
	htmlContents = response.content

# BeautifulSoupを使ってHTMLを解析する. soup = BeautifulSoup(htmlContents.decode("utf-8", "ignore"), "html.parser")
# タグの内容を取得する tags = soup.find(TARGET_TAG, attrs={"name": TARGET_ATTR})
if tags and "content" in tags.attrs: contents = tags["content"] print(contents) else: print("タグが見つかりません")
応用として、プログラム "getHtmlTags1.py" の変数 TARGET_URL を他のサイトにしたり、変数 TARGET_TAGTARGET_ATTR の値を変更して、他のタグの内容を取得できるようにしてみよう。

グラフを描く

Python では関数のグラフを描くことも簡単に出来る。
まず、pipコマンドを使って、グラフ描画の外部ライブラリ Matplotlib と科学技術計算ライブラリ NumPy を導入しよう。
pip install matplotlib
pip install numpy
quadraticFunction.py
# メイン・プログラム =======================================================
# モジュールをimportする.
try:
	import numpy as np
	from matplotlib import pyplot as plt
except ImportError as e:
	print(f"外部ライブラリをインストールしてください ... {e}")
else:
	# グラフの描画範囲
	X_MIN = -8.0
	X_MAX = +8.0
	Y_MIN = -8.0
	Y_MAX = +8.0

	# プロットするデータセット(list)を生成
	xList = np.arange(X_MIN, X_MAX, 0.1).tolist()
	yList = [x ** 2 - 3 * x - 4 for x in xList]
	# グラフにプロットするデータ
	plt.plot(xList, yList)

	# 周囲の枠(スパイン)を消す
	for spine in plt.gca().spines.values():
	    spine.set_visible(False)
	# X軸、Y軸を最大値・最小値を設定する
	plt.xlim(-8, +8)
	plt.ylim(-8, +8)
	# X軸、Y軸を描く
	plt.axhline(0, color='black', linewidth=1.0)
	plt.axvline(0, color='black', linewidth=1.0)
	# X軸、Y軸のスケールを合わせる
	plt.gca().set_aspect('equal', adjustable='box')
	# 目盛りを描く
	plt.minorticks_on()
	plt.grid(which='both')
	plt.grid(which='major', linestyle='-', linewidth=0.5, color='gray')
	plt.grid(which='minor', linestyle=':', linewidth=0.5, color='gray')
	# グラフを表示する
	plt.show()
2次関数のグラフ
プログラム "quadraticFunction.py" を実行してみてほしい。左図のように 2次関数 \( x^2 - 3x - 4 \) のグラフを表示する。

まず、numpy.arangeメソッドを使って、X_MIN から X_MAX まで、0.1刻みの小数リスト xList を生成する。
次に、式 [x ** 2 - 3 * x - 4 for x in xList] では、for文 を使って先ほどのリスト xList から1つずつ\( x \)の値を取り出し、2次関数 \( x^2 - 3x - 4 \) に代入して \(y \) の値をリストにして yList に代入する。
リスト xListyList がグラフにプロットする数列となるが、これらを生成するのに繰り返し制御を使う必要はない。

あとは、Matplotlibのグラフ表示を整える部分で、コメントに記しているとおりだ。

2次関数の解の公式とグラフ

中学3年生の数学で2次関数の解の公式を学ぶ。
この解の公式を Python プログラムで書くと同時に、その2次関数をグラフに描いてみることにする。
2次関数の解の公式は次の通り。
\[ \displaystyle x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} \quad \text{ただし} \ a \neq 0 \]
プログラムは、係数の \( a, b, c \) をキーボード入力するものとする。
解の公式の前提条件は \( a \neq 0 \) なので、分母がゼロになることはない。つまり、常に除算は成立する。ただし、プログラムでは \( a \) の値として0を入力させないようにする必要がある。

次に、平方根の部分 \( \displaystyle \sqrt{b^2 - 4ac} \) に注意する。
中学の数学では平方根の中身が負数であってはならない。負数になると、虚数解といって、これは高校2年生で学ぶ内容である。
また、平方根の中身がゼロの場合は重解となり、\( \pm \) が意味を成さなくなる。
プログラムでは、虚数解や重解にも対応できるよう、あからじめ \( D = {b^2 - 4ac} \) を計算し、Dが正か負かゼロかによって場合分けして計算する。
2次関数のグラフ
プログラム "quadraticFormula.py" を実行してみてほしい。2次関数 \( 2 x^2 + 6x + 2 \) を解かせると、コンソールに下記のように入力表示し、左図のグラフを表示する。
ax^2 + bx + c, ただし a≠0
a = 2
b = 6
c = 2
(実数解) x1 = -0.3819660112501051, x2 = -2.618033988749895
それでは、Pythonプログラム "quadraticFormula.py" をご覧いただきたい。
quadraticFormula.py
import math
try:
	import numpy as np
	from matplotlib import pyplot as plt
except ImportError as e:
	print(f"外部ライブラリをインストールしてください ... {e}")
	exit()
すでに紹介した標準ライブラリ math と、外部ライブラリ NumPymatplotlib を利用する。
quadraticFormula.py
# 2次方程式 ax^2 + bx + c = 0 の係数を入力
print("ax^2 + bx + c, ただし a≠0")
a = float(input("a = "))
b = float(input("b = "))
c = float(input("c = "))

# aがゼロの場合は計算しない
if (a == 0):
	print("aには0以外の値を入力してください")
	exit()
キーボードから係数の \( a, b, c \) を入力する。\( a \) がゼロの時はメッセージを表示してプログラムを終了する。
quadraticFormula.py
# 判別式 (b^2 - 4ac) を計算する
D = b ** 2 - 4 * a * c

# 判別式に基づいて解を求める if D > 0: # 異なる2つの実数解 x1 = (-b + math.sqrt(D)) / (2 * a) x2 = (-b - math.sqrt(D)) / (2 * a) print(f"(実数解) x1 = {x1}, x2 = {x2}") elif D == 0: # 重解(実数解) x = -b / (2 * a) print(f"(重解) x = {x}") else: # 虚数解 realPart = -b / (2 * a) imaginaryPart = math.sqrt(-D) / (2 * a) print(f"(虚数解) x1 = {realPart} + {imaginaryPart}i, x2 = {realPart} - {imaginaryPart}i")
\( D = {b^2 - 4ac} \) を計算し、Dが正か負かゼロかによって、if文による条件分岐を行う。
  • \( D \) が正数のときは、上述の解の公式の通りに計算し、2つの実数解を変数 x1, x2 に代入する。
  • \( D \) がゼロのときは、\( \sqrt{b^2 - 4ac} \) の部分は計算せず、重解を x に代入するする。
  • \( D \) が負数のときは、虚数解になるので、実数部分を realPart に、虚数部分を imaginaryPart に代入する。
これ以降は2次関数のグラフを描く処理である。
quadraticFormula.py
# 2次関数のグラフを描く
if D > 0:
	xw = abs(x1 - x2)
	xMin = int(x1 - xw if x1 <= x2 else x2 - xw) - 1
	xMax = int(x2 + xw if x1 > x2 else x2 + xw) + 1
	yMin = -abs(xMax - xMin) / 2
	yMax = -yMin
elif D == 0:
	xMin = x - 8.0
	xMax = x + 8.0
	yMin = -abs(xMax - xMin) / 2
	yMax = -yMin
else:
	x = 0
	y = a * x ** 2 + b * x + c
	if y >= 0:
		yMin = -1.0
		yMax = int(y * 2.0)
		xw = abs(yMax - yMin)
	else:
		yMax = +1.0
		yMin = int(y * 2.0)
		xw = abs(yMax - yMin)
	xMin = int(realPart - xw)
	xMax = int(realPart + xw)
グラフの4象限
まず、グラフ領域 x, y それぞれの最大値と最小値)を決める。
これも \( D \) による場合分けを行った。\( D \) が正数のときは、グラフがX軸を交差する。つまり、第1~4象限の全てにグラフが描かれる可能性がある。\( D \) がゼロのときは、グラフがX軸に接する(交差はしない)。つまり、第1・2または第3・4象限にグラフが描かれる可能性がある。\( D \) が負数のときは、グラフはX軸に接しない(X軸から離れた位置にある)。つまり、第1・2または第3・4象限にグラフが描かれる可能性がある。
これらの前提を踏まえ、与えられた2次方程式に合わせてグラフ領域が可変になるようにした。
quadraticFormula.py
# プロットするデータセット(list)を生成
xList = np.arange(xMin, xMax, 0.1).tolist()
yList = [a * x ** 2 + b * x + c for x in xList]
# グラフにプロットするデータ
plt.plot(xList, yList)
プロットするx座標を xList に、y座標を yList に代入する。
quadraticFormula.py
# X軸、Y軸を描く
plt.axhline(0, color='black', linewidth=1.0)
plt.axvline(0, color='black', linewidth=1.0)
# X軸、Y軸のスケールを合わせる
plt.gca().set_aspect('equal', adjustable='box')

# 目盛りをXY軸上に移動する
ax = plt.gca()								# 現在の軸を取得
ax.spines['left'].set_position('zero')		# Y軸をX=0の位置に描く
ax.spines['bottom'].set_position('zero')	# X軸をY=0の位置に絵泊
ax.spines['right'].set_color('none')		# 右側のスパインを非表示にする
ax.spines['top'].set_color('none')			# 上側のスパインを非表示にする

# 現在のX軸、Y軸の目盛りを取得して「0」を削除 xticks = ax.get_xticks().tolist() # X軸の目盛りを取得する yticks = ax.get_yticks().tolist() # Y軸の目盛りを取得する if 0 in xticks: xticks.remove(0) # X軸の目盛りから0を削除する if 0 in yticks: yticks.remove(0) # Y軸の目盛りから0を削除する
# 更新した目盛りを設定する ax.set_xticks(xticks) ax.set_yticks(yticks)
# 小目盛りとグリッドを描画する plt.minorticks_on() plt.grid(which='both') plt.grid(which='major', linestyle='-', linewidth=0.5, color='gray') plt.grid(which='minor', linestyle=':', linewidth=0.5, color='gray') # グラフを表示する plt.show()
最後に、グラフの目盛りを設定して、plt.show を使ってグラフを表示する。
メモリの設定部分が長いのだが、デフォルトでグラフの外周に描かれる目盛りと値を、X軸とY軸の上にプロットするよう移動している。

グラフ領域を計算するときに説明したとおり、2次関数のグラフがX軸と2箇所で交差すれば2つの実数解があり、X軸と接する(交差しない)ときには重解となり、X軸から離れているときには虚数解になるというのが、これらのグラフから視覚的に分かるだろう。

さて、高校数学で複素数について深掘りした方は、X軸を複素平面 \( a+ bi \) に拡張することで、グラフが曲面となり、Y軸を交差するところが表れる。
3次元のグラフも今回使った外部ライブラリ matplotlib で描画することができるので、課題として取り組んでみてほしい。

練習問題

次回予告

Python では、組み込み関数標準ライブラリ外部ライブラリにないが、よく使う処理を関数に書くことができる。これをユーザー定義関数と呼ぶ。
次回は、作成したユーザー定義関数を使ってグラフを描いたり、書いてはいけない関数について学ぶ。

コラム:標準ライブラリを使ったスクレイピング

本文の "getHtmlTaghs1.py" のような処理をスクレイピングと呼ぶ。BeautifulSoup は優れた外部ライブラリだが、本文の要求であれば、標準ライブラリだけでプログラムを書くことができる。外部ライブラリを使わずに動かすことができれば、プログラム配布先に Python の実行環境がありさえすれば動く。同梱の "getHtmlTaghs2.py" をご覧いただきたい。
getHtmlTags2.py
# 標準ライブラリをimportする.
import urllib.request
from html.parser import HTMLParser

# スクレイピング対象のURL
TARGET_URL = "https://www.pahoo.org/"
# 取り出したいタグ
TARGET_TAG = "meta"
# タグの属性
TARGET_ATTR = "description"

class scraping(HTMLParser):
	"""スクレイピング・クラス
	
	Note:
		HTMLParserを継承する.
	"""

	def __init__(self, targetTag, targetAttr=""):
		"""コンストラクタ
		
		Args:
			targetTag(str): 取得したいHTMLタグ
		
		Returns:
			None
		"""
		super().__init__()
		self.targetTag  = targetTag
		self.targetAttr = targetAttr
		self.inTargetTag = False
		self.data = []

	def handle_starttag(self, tag, attrs):
		if tag == self.targetTag:
			if (self.targetAttr != ""):
				attrsDict = dict(attrs)
				if attrsDict.get("name") == TARGET_ATTR:
					self.data.append(attrsDict.get("content"))
			else:
				self.inTargetTag = True

	def handle_endtag(self, tag):
		if tag == self.targetTag:
			self.inTargetTag = False

	def handle_data(self, data):
		if self.inTargetTag:
			self.data.append(data)

# メイン・プログラム =======================================================
# HTMLコンテンツを取得する.(UTF-8固定)
response = urllib.request.urlopen(TARGET_URL)
htmlContents = response.read().decode("utf-8")

# HTMLコンテンツを解析する.
scrape = scraping(TARGET_TAG, TARGET_ATTR)
scrape.feed(htmlContents)

# タグの内容を表示する.
print(scrape.data)
(この項おわり)
header