LoginSignup
5
5

More than 3 years have passed since last update.

Pythonの組み込み関数69個を制覇する 第5回 l~o

Last updated at Posted at 2019-12-29

Pythonでは、非常に多くの組み込み関数(Built-in Functions)が用意されており、ライブラリをimportせずとも様々な処理を行うことができます。
基本に立ち返って、組み込み関数の使い方を整理して行きたいと思います。
j, kから始まる組込み関数は現在のところないので、第5回はlからの開始です。

尚、実行例はWindows Subsystem for Linux 2 (WSL2)のUbuntu18.04にインストールしたPython3.7.5で作成しています。

(注意事項)
更新の期間が空いた結果、前回までの記事とPythonのマイナーバージョンおよび実行環境が異なっていますのでご注意ください。
また、執筆時現在、Python3.8.0がリリースされていますが、本シリーズではPython3.7系での記述を行っていますので、そちらも留意いただければと思います。

Pythonの組み込み関数69個を制覇する 第1回 a~b
Pythonの組み込み関数69個を制覇する 第2回 c~d
Pythonの組み込み関数69個を制覇する 第3回 e~g
Pythonの組み込み関数69個を制覇する 第4回 h~i
Pythonの組み込み関数69個を制覇する 第6回 p~r

関数の使い方

各関数の使い方を記述していきます。詳細な使い方は他の記事に譲るとして、ここでは簡単な使用例を中心に掲載していきます。

len()

渡したオブジェクトの持つ要素の個数を返却します。
引数に渡せるのは、文字列、リストやタプルなどのシーケンスや、辞書・セットなどのコンテナです。

>>> # 文字列型
... len('The quick brown fox jumps over the lazy dog')
43
>>> # リスト
... len(['fox', 'dog', 'otter', 'cat'])
4
>>> # タプル
... len((1, 1, 2, 3, 5, 8, 13, 21, 34, 55,))
10
>>> # 辞書
... len({'Hello': 'World', 'Good bye': 'World'})
2
>>> # セット
... len({2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31})
11
>>> # rangeオブジェクト
... len(range(100))
100 
>>> # `__len__` を実装すると長さを取得できる
...  class Stock(object):
...     def __init__(self, data):
...         self._data = data
...     def __len__(self):
...         return len(self._data)
...
>>> stock = Stock({'orange': 10, 'strawberry': 3, 'melon': 5})
>>> len(stock)
3

ちなみに、CPythonの実装では、lenの上限はsys.maxsize以下に制限されています。

>>> class MaxLen(object):
...     def __len__(self):
...         return sys.maxsize
...
>>> len(MaxLen())
9223372036854775807
>>> class OverMax(object):
...     def __len__(self):
...         return sys.maxsize + 1
...
>>> # sys.maxsizeを超えるとエラーになる
... len(OverMax())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: cannot fit 'int' into an index-sized integer

実際にはmaxsizeのリストを作ろうとするとメモリが足りなくなりました。

>>> [1] * sys.maxsize
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError
>>> l = [1 for i in range(sys.maxsize)]
# メモリ不足でWSL2が落ちた

MemoryErrorになるか、もしくは落ちるかは環境によって異なるようなので、気になる方は安全に配慮した上で試してみてください。以前私がWSL1で試した際には、後者の例で segmentaiton fault が発生しPythonがエラー終了しました。

list()

リスト型のオブジェクトをつくって返却します。
引数には、シーケンス、イテレーション可能なオブジェクト、イテレータを渡すことができます。

>>> # 引数なしなら要素のない空リスト
... list()
[]
>>> # 文字列
... list('curry and rice')
['c', 'u', 'r', 'r', 'y', ' ', 'a', 'n', 'd', ' ', 'r', 'i', 'c', 'e']
>>> # リスト
... list(['Mystery', 'SF', 'Fantasy', 'Romance'])
['Mystery', 'SF', 'Fantasy', 'Romance']
>>> # タプル
... list(('Classic', 'Rock', 'R&B', 'Jazz',))
['Classic', 'Rock', 'R&B', 'Jazz']
>>> # range
... list(range(1, 10, 2))
[1, 3, 5, 7, 9]
>>> # 辞書
... list({'Harry': 'Potter', 'Ron': 'Weasley', 'Draco': 'Malfoy'})
['Harry', 'Ron', 'Draco']
>>> # イテレータ
... list(iter(functools.partial(random.randint, 1, 10), 5))
[10, 3, 7, 2, 3, 9, 4, 4, 7, 1, 10, 8, 7, 1, 3, 3, 10, 2, 6, 4]

listオブジェクト生成のタイミングでイテレータの評価が行われます。


>>> m = map(int, "1 2 3 4 5".split())
>>> next(m)
1
>>> next(m)
2
>>> list(m)
[3, 4, 5]
>>> # イテレータの要素がすべて消費されたので、StopIterationになる
... next(m)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

locals()

呼び出されたローカルな名前空間におけるローカル変数と値のマッピングを返却します。

>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}

対話コンソール上で呼び出した場合は、グローバル変数と同じになります。

>>> locals() == globals()
True

関数内では関数ローカルな値の一覧を返します。


>>> def locals_in_func(*args, **kwargs):
...     a = 1
...     b = 2
...     c = args[:]
...     d = kwargs
...     def _local_func():
...         return 100
...     f = lambda x: 'Paw!'
...     return locals()
...
>>> from pprint import pprint
>>> pprint(locals_in_func(1, 2, 3, 4, **{'Tissue': 'Paper', 'Toilet': 'Paper'}))
{'_local_func': <function locals_in_func.<locals>._local_func at 0x7efecffa0dd0>,
 'a': 1,
 'args': (1, 2, 3, 4),
 'b': 2,
 'c': (1, 2, 3, 4),
 'd': {'Tissue': 'Paper', 'Toilet': 'Paper'},
 'f': <function locals_in_func.<locals>.<lambda> at 0x7efecffb5050>,
 'kwargs': {'Tissue': 'Paper', 'Toilet': 'Paper'}}

map()

関数とイテラブルを引数にわたすと、イテラブルの各要素に関数を適用するmapオブジェクトというイテレータを返却します。
リストの要素を一括で処理したい場合などに便利です。

>>> # 返り値はmapオブジェクト
... map(str, range(10, 0, -2))
<map object at 0x7f2aaf3234e0>
>>> # rangeの各要素を文字列化する
>>> for i in map(str, range(10, 0, -2)):
...     print(i)
...
10
8
6
4
2
>>> # リストの全要素を二乗する
... [i for i in map(lambda x: x * x, [1, 2, 3, 4, 5])]
[1, 4, 9, 16, 25]
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5]))
[1, 4, 9, 16, 25]
>>> # ユニコードのコードポイントを文字列に変換する
... list(map(chr, [8593, 8593, 8595, 8595, 8592, 8594, 8592, 8594, 66, 65]))
['↑', '↑', '↓', '↓', '←', '→', '←', '→', 'B', 'A']
>>> # 複数の引数を取る関数の場合、必要な引数の数だけiterableを渡す
... for xy in map(lambda x, y: x * y, (1, 2, 3, 4, 5), (1, 10, 100, 1000, 10000)):
...     print(xy)
...
1
20
300
4000
50000

map()に渡した関数は、各要素の呼び出し時に評価されます。

>>> def echo_twice(arg):
...     print(arg, arg)
...
>>> m = map(echo_twice, ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'])
>>> next(m)
Sunday Sunday
>>> next(m)
Monday Monday
>>> next(m)
Tuesday Tuesday
>>> next(m)
Wednesday Wednesday
>>> list(m)
Thursday Thursday
Friday Friday
Saturday Saturday
[None, None, None]

next()が呼ばれたタイミングで対象の要素が表示されるので、各関数は呼び出し時に評価されることがわかります。

max()

渡された引数の中の最大値を返却します。
引数は一つ以上の任意個の値を渡すことが可能です。ただし、引数の個数が一つの場合はイテラブルである必要があります。

>>> max(5, 2, 4, 1, 6, 0)
6
>>> numbers = [2, 5, 3, 1, 29, 0, -345]
>>> max(numbers)
29
>>> # 文字列も最大値をとれる
... max(['m', 'A', 'x'])
'x'
>>> # リストの最大値
... max([1, 3, 5], [2, 4, 6], [-3, -2, 10])
[2, 4, 6]
>>> # 数値と文字列
... max(1, 3, 7, 'S', 't', 'r')
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: '>' not supported between instances of 'str' and 'int'
>>> # 引数が一つの場合はiterableでないといけない
... max(10000)
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: 'int' object is not iterable

引数にiterableを渡すパターンでは、中身が空の要素を渡した場合はエラーが発生します。
default引数を使うことで、空の場合の返り値を定義することができます。

>>> # 空の場合の挙動を定義できる
... max([], default=100)
100
>>> #  defaultを指定せずに空のiterableを渡すとエラーになる
... max([])
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: max() arg is an empty sequence

max()関数は list.sort()sorted() 関数と同様、key引数を渡すことができます。max()は各要素にkey引数に指定された関数を適用し、その結果を最大値取得のためのソートに利用します。
key引数は、リストの各要素を受け取り、ソートに使う要素を返却するような関数オブジェクトです。
key引数の使い方は、ソート HOW TO が参考になります。

>>> max(-10, -20, -100000, key=abs)
-100000

最大値を取得するためには、比較を行う各要素間で __lt__() メソッドと__eq__() メソッドがサポートされていれば十分なので、自作クラスでの最大値を定義することもできます。

>>> # 自分で定義したクラス
... class Grade:
...     def __init__(self, point):
...         self.point = point
...     def __lt__(self, other):
...         return self.point < other.point
...     def __eq__(self, other):
...         return self.point == other.point
...     def __repr__(self):
...         return str(self.point)
...
>>> students = {'John': Grade(35), 'Jessy': Grade(85), 'Jack': Grade(0)}
>>> # Gradeが最大となる要素を取得する
... max(students.items(), key=lambda x: x[1])
('Jessy', 85)

memoryview()

与えられたオブジェクトの メモリビュー オブジェクトを作成して返却します。
メモリビューを利用することで、値のコピーをすることなく下層のメモリ配列などの内部データへのアクセスをすることができます。
メモリビューを作成するためには、対象のオブジェクトがバッファプロトコル をサポートしている必要があります。例えば、bytesやbytearray、標準ライブラリのarray.arrayなどがバッファプロトコルをサポートしています。

>>> # bytes型へのメモリビュー
... m = memoryview(b'Hello,World')
>>> m
<memory at 0x7fb4033fae20>
>>> m.itemsize
1
>>> # bytes型は読み取り専用
... m.readonly
True
>>> # readonly = True なので、書き込みはできない
... m[0] = 71
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: cannot modify read-only memory
>>> m.nbytes
11
>>> m.tolist()
[72, 101, 108, 108, 111, 44, 87, 111, 114, 108, 100]
>>> m.tobytes()
b'Hello,World'
>>> # bytearray型へのメモリビュー
... original = bytearray(b'Hello,World')
>>> ba = memoryview(original)
>>> ba.readonly
False
>>> # readonly = False なので書き込みが可能
... ba[0] = 71
>>> ba.tobytes()
b'Gello,World'
>>> # 元のbytearrayも書き換えられている。
... original
bytearray(b'Gello,World')

memoryviewクラスはcastメソッドをもっており、バイト列の値を読み替えできます。

>>> import array
>>> # unsigned short の arrayを生成
... us = array.array('H', [2**16-1])
>>> us
array('H', [65535])
>>> mv_us = memoryview(us)
>>> mv_us.hex()
'ffff'
>>> mv_us.tolist()
[65535]
>>> # unsigned char型の配列に変換
... mv_uc = mv_us.cast('B')
>>> mv_uc.tolist()
[255, 255]
>>> # signed short の配列に変換
... mv_ss = mv_uc.cast('h')
>>> mv_ss.hex()
'ffff'
>>> mv_ss.tolist()
[-1]

もとの配列の要素の値は65535でしたが、C言語でいうところのunsigned char型の配列を介して、強制的にsigned short型(16bit)で解釈させることで、Pythonのリストに変換すると-1になってしまいました。hex()関数からわかるように、メモリ上の値は変わっていません。

min()

max()関数と同じ構造になっており、渡された引数の中の最小値を返却します。
引数は一つ以上の任意個の値を渡すことが可能です。ただし、引数の個数が一つの場合はイテラブルである必要があります。

>>> min(5, 2, 4, 1, 6, 0)
0
>>> numbers = [2, 5, 3, 1, 29, 0, -345]
>>> min(numbers)
-345
>>> min(['m', 'A', 'x'])
'A'
>>> min([1, 3, 5], [2, 4, 6], [-3, -2, 10])
[-3, -2, 10]
>>> min(1, 3, 7, 'S', 't', 'r')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'str' and 'int'
>>> min(10000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable

key引数でソートの値を指定できる点、default引数でイテラブルが空の場合の返却値を定義できる点もmax()と同じ構造です。

>>> min([], default=-1)
-1
>>> min([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence
>>> min(-10, -20, -100000, key=abs)
-10

next()

引数にイテレータオブジェクトを渡すと、 __next__() メソッドを呼び出して次の要素を一つ返却します。
返却できる値がない場合は、第2引数に指定したデフォルト値を返します。
デフォルト値が指定されていない場合はStopIteration例外を送出します。

>>> # rangeオブジェクトをイテレータ化する
... it = iter(range(3))
>>> next(it)
0
>>> next(it)
1
>>> next(it)
2
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> # default値を指定する
... next(it, 1000000)
1000000
>>> next(it, 1000000)
1000000
>>> # キーワードでは指定できない
... next(it, default=1000000)
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: next() takes no keyword arguments
>>> # ジェネレータ式
... gen = (c for c in 'Sword')
>>> next(gen)
'S'
>>> next(gen)
'w'
>>> next(gen)
'o'
>>> next(gen)
'r'
>>> next(gen)
'd'
>>> next(gen)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

object()

Pythonを構成する最も基本的なオブジェクトを生成して返却します。
objectはすべてのクラスのベースクラスです。

>>> # 新しいobjectインスタンスを生成する
... ob = object()
>>> # すべてのクラスはobjectのサブクラス
... issubclass(object, int)
False
>>> issubclass(int, object)
True
>>> class MyClass: pass
...
>>> issubclass(MyClass, object)
True
>>> # object自身もobjectのサブクラスと判定される
... issubclass(object, object)
True
>>> # objectは __dict__ メソッドを持たないので、属性をもてない
... ob.hoge = 'fuga'
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: 'object' object has no attribute 'hoge'

oct()

引数に整数を渡すと、頭に"0o"のついた 8進数表現の文字列として変換してくれます。整数型ではなく、文字列を返すところに注意してください。結果はPythonの式としてeval()で評価可能です。

>>> oct(0)
'0o0'
>>> oct(7)
'0o7'
>>> oct(8)
'0o10'
>>> oct(63)
'0o77'
>>> eval(oct(63))
63

open()

引数に渡した名前のファイルを開き、ファイルの読み書きを行うファイルオブジェクトを返却します。
第2引数に渡すmodeの値によって、生成されるファイルオブジェクトの挙動が変わります。
モードは文字列で、読み込み(r)か書き込み(w, x, a)か、および、テキストかバイナリか(t, b)の2軸で決まります。デフォルトでは、テキストの読み込みモードでファイルを開きます。

>>> # r(読み込み)では、指定したファイルが存在しない場合エラーになる。
... file1 = open('test.txt', 'r')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'
>>> # w(書き込み)では、指定したファイルが存在しない場合作成される
... file1 = open('test.txt', 'w')
>>> file1.write('New file')
8
>>> file1.close()
>>> file1
<_io.TextIOWrapper name='test.txt' mode='w' encoding='UTF-8'>
>>> # ファイルが作成されたので読み込みが可能になった
... file1 = open('test.txt', 'r')
>>> file1.read()
'New file'
>>> file1.close()
>>> # 排他書き込み(x)では、ファイルが存在したらエラーになる
... file1 = open('test.txt', 'x')
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
FileExistsError: [Errno 17] File exists: 'test.txt'
>>> # 追記書き込み(a)では、ファイルの末尾に書き込みを行う
... file1 = open('test.txt', 'r')
>>> file1.read()
'New file'
>>> file1.close()
>>> file1 = open('test.txt', 'a')
>>> file1.write('\nHello, Hello')
13
>>> file1.close()
>>> file1 = open('test.txt', 'r')
>>> file1.read()
'New file\nHello, Hello'
>>> file1.close()
>>> # 書き込み(w)では、ファイル内容が上書きされる
... file1 = open('test.txt', 'w')
>>> file1.write('New Line!!!')
11
>>> file1.close()
>>> file1 = open('test.txt', 'r')
>>> file1.read()
'New Line!!!'

モードに b を付加することでバイナリファイルも読み込むことができます。

$ ls
ichi_taro3.png
$ python3
Python 3.7.4 (default, Jul 12 2019, 20:57:46)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> # pngファイルの中身をバイナリモードで読んでみる
... picture = open('ichi_taro3.png', 'rb')
>>> data = picture.read()
>>> data[:20]
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\x90'
>>> picture.close()
>>> # 無理にテキストモードで開こうとすると
... picture = open('ichi_taro3.png', 'rt')
>>> content = picture.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/linuxbrew/.linuxbrew/bin/../Cellar/python/3.7.4/lib/python3.7/codecs.py", line 322, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte

open() で返されるファイルオブジェクトはコンテキストマネージャを備えており、with文内でopen()を使うことで、withブロックを抜けたタイミングでファイルが自動でクローズされます。通常ファイル操作する場合は、with文とともに利用することがオススメです。
コンテキストマネージャ型

>>> with open('test.txt', 'r') as file1:
...     file1.read()
...
'New Line!!!'
>>> # withブロックを抜けてcloseされたファイルは読めない。
... file1.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.

ord()

一文字のUnicode文字を与えると、Unicodeのコードポイントを整数で返却します。
ちょうど、chr()関数の逆の動きです。

>>> ord('A')
65
>>> ord('Æ')
198
>>> ord('Д')
1044
>>> ord('へ')
12408
>>> ord('嵐')
23888
>>> ord('🌝')
127773
>>> chr(ord('🌝'))
'🌝'

第6回に続く

次回は pow() から

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5