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

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](https://qiita.com/ichi_taro3/items/cd71a8e43040abb446a1)
[Pythonの組み込み関数69個を制覇する 第2回 c～d](https://qiita.com/ichi_taro3/items/696b355d79d01a810381)
[Pythonの組み込み関数69個を制覇する 第3回 e～g](https://qiita.com/ichi_taro3/items/c866b7124415464e8ef1)
[Pythonの組み込み関数69個を制覇する 第4回 h～i](https://qiita.com/ichi_taro3/items/ee55257338b32c073bad)
[Pythonの組み込み関数69個を制覇する 第6回 p～r](https://qiita.com/ichi_taro3/items/2c2b399b762f5800fe82)


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

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

```Python
>>> # 文字列型
... 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以下に制限されています。

```Python
>>> 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のリストを作ろうとするとメモリが足りなくなりました。

```Python
>>> [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()
リスト型のオブジェクトをつくって返却します。
引数には、シーケンス、イテレーション可能なオブジェクト、イテレータを渡すことができます。

```Python
>>> # 引数なしなら要素のない空リスト
... 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オブジェクト生成のタイミングでイテレータの評価が行われます。

```python

>>> 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()
呼び出されたローカルな名前空間におけるローカル変数と値のマッピングを返却します。

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

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

```Python
>>> locals() == globals()
True
```

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

```python

>>> 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オブジェクトというイテレータを返却します。
リストの要素を一括で処理したい場合などに便利です。

```Python
>>> # 返り値は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()に渡した関数は、各要素の呼び出し時に評価されます。

```Python
>>> 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()

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

```Python
>>> 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引数を使うことで、空の場合の返り値を定義することができます。

```Python
>>> # 空の場合の挙動を定義できる
... 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](https://docs.python.org/ja/3.8/howto/sorting.html) が参考になります。

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

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

```Python
>>> # 自分で定義したクラス
... 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()
与えられたオブジェクトの [メモリビュー](https://docs.python.org/ja/3.7/library/stdtypes.html#typememoryview) オブジェクトを作成して返却します。
メモリビューを利用することで、値のコピーをすることなく下層のメモリ配列などの内部データへのアクセスをすることができます。
メモリビューを作成するためには、対象のオブジェクトが[バッファプロトコル](https://docs.python.org/ja/3.7/c-api/buffer.html#buffer-protocol) をサポートしている必要があります。例えば、bytesやbytearray、標準ライブラリのarray.arrayなどがバッファプロトコルをサポートしています。

```Python
>>> # 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'
```


```Python
>>> # 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メソッドをもっており、バイト列の値を読み替えできます。

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

```Python
>>> 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()と同じ構造です。

```Python
>>> 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例外を送出します。

```Python
>>> # 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はすべてのクラスのベースクラスです。

```Python
>>> # 新しい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()で評価可能です。

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

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

```python
>>> # 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` を付加することでバイナリファイルも読み込むことができます。

```python
$ 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文とともに利用することがオススメです。
[コンテキストマネージャ型](https://docs.python.org/ja/3/library/stdtypes.html#context-manager-types)

```python
>>> 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()](https://qiita.com/ichi_taro3/items/696b355d79d01a810381#chr)関数の逆の動きです。

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

## [第6回](https://qiita.com/ichi_taro3/items/2c2b399b762f5800fe82)に続く

[次回](https://qiita.com/ichi_taro3/items/2c2b399b762f5800fe82)は pow() から