見出し画像

Python実践入門 ──言語の力を引き出し、開発効率を高める(第8章組み込み関数と特殊メソッド)

■組み込み関数
 何もインポートすることなくいつでも利用できるPythonの関数

■特殊メソッド
 メソッド名の前後に_がついているメソッドで、
 Pythonから暗黙的に呼び出されます。

■今回勉強に利用した本


8.1組み込み関数 -いつでも利用できる関数-

オブジェクトの型を調べる関数

isInstance(), issubclass() - 動的な型判定

>>> d = {}
>>> isinstance(d, dict)
True
>>> isinstance(d, object)
True
>>> issubclass(dict, object)
True
>>> issubclass(bool, (list, int, dict))
True

callable() - 呼び出し可能オブジェクトを判定

>>> callable(isinstance)
True
>>> callable(Exception)
True
>>> callable("".split)
True


オブジェクトの属性に関する関数

hasattr() - オブジェクトの属性の有無を判定

>>> import json
>>> import os
>>> 
>>> def is_package(module_or_package): 
...  return hasattr(module_or_package, '__path__')
... 
>>> 
>>> is_package(json)
True
>>> is_package(os)
False

getattr(), setattr(), delattr() - オブジェクトの属性を操作する

>>> class Mutable:
...  def __init__(self, attr_map):
...   for k, v in attr_map.items():
...    setattr(self, str(k), v)
... 
>>> m = Mutable({'a':1, 'b':2})
>>> m.a
1
>>> 
>>> attr = 'b'
>>> getattr(m, attr)
2
>>> 
>>> delattr(m, 'a')
>>> m.a
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'Mutable' object has no attribute 'a'


イテラブルなオブジェクトを受け取る関数

zip() - 複数のイテラブルの要素を同時に返す。

>>> x = [1,2,3]
>>> y = [4,5,6]
>>> zip(x,y)
<zip object at 0x7f65deca9f00>
>>> list(zip(x,y))
[(1, 4), (2, 5), (3, 6)]

sorted() - イテラブルの要素を並べ替える。

>>> x = [1,4,3,5,2]
>>> y = [1,4,3,5,2]
>>> 
>>> x.sort()
>>> x
[1, 2, 3, 4, 5]
>>> 
>>> sorted(y)
[1, 2, 3, 4, 5]
>>> y
[1, 4, 3, 5, 2]
>>> 
>>> sorted(y, reverse=True)
[5, 4, 3, 2, 1]
>>> 

filter() - イテラブルの要素を絞り込む

>>> x = (1,4,3,5,2)
>>> list(filter(lambda i:i>3,x)) 
[4, 5]
>>>
​>>> x = (1,0,None,2,[],'python')
>>> list(filter(None,x))
[1, 2, 'python']
>>> from operator import itemgetter
>>> d = {'word': 'python', 'count': 3}
>>> f = itemgetter('count')
>>> f(d)  
3 # d['count']を返す
>>> f = itemgetter('count', 'word')
>>> f(d) 
(3, 'python')  # (d['count'], d['word'])を返す

all(), any() -  真理値を返す

>>> all(['python', 'practice', 'book'])
True
>>> all(['python', 'practice', ''])
False
>>> any(['python', '', ''])
True

# 真の値がないのでFalse
>>> any(['', '', ''])
False


8.2特殊メソッド - Pythonが暗黙的に呼び出す特殊メソッド

■目印
メソッド名の前後に_が2つついています。__メソッド名__

__str__(),__repr__() - オブジェクトを文字列で表現する。

>>> s = 'string'
# オブジェクト名のみを入力した際は__repr__()が呼ばれます。
>>> s
'string'
組み込み関数print()に渡された際は__str__()が呼ばれます。
>>> print(s)
string

__bool__() - オブジェクトを真理値で評価する

>>> class QueryParams:
...   def __init__(self, params):
...     self.params = params
...   def __bool__(self):
...     return bool(self.params)
...
>>> query = QueryParams({})
>>> bool(query)
False
>>> query = QueryParams({'key': 'value'})
>>> bool(query)
True

__call__() - インスタンスを関数のように扱う

>>> class Adder:
...   def __init__(self):
...     self._values = []
...   def add(self, x):
...     self._values.append(x)
...   def __call__(self):
...     return sum(self._values)
...
>>> adder = Adder()
>>> adder.add(1)
>>> adder.add(3)
>>> adder()
4
>>> adder.add(5)
>>> adder()
9
# 関数を作成すると、自ずと__call__()が実装されている。
>>> def f():
...   return 1
...
>>> dir(f)
['__annotations__', '__call__', '__class__', ...]
>>> type(f)
<class 'function'>

属性への動的なアクセス

__setattr__() - 属性への代入で呼び出される

__setattr__()の内部で自分自身に属性を追加する際は、必ず組み込み関数super()を使って基底クラスの__setattr__()を呼び出す。
>>> class Point:
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
...   def __setattr__(self, name, value):
...     if name not in ('x', 'y'):
...       raise AttributeError('Not allowed')
...     super().__setattr__(name, value)
...
>>> p = Point(1, 2)
>>> p.z = 3
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "<stdin>", line 7, in __setattr__
AttributeError: Not allowed
>>> p.x = 3
>>> p.x
3

__delattr() - 属性の削除で呼び出される

>>> class Point:
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
...   def __delattr__(self, name):
...     if name in ('x', 'y'):
...       raise AttributeError('Not allowed')
...     super().__delattr__(name)
...
>>> p = Point(1, 2)
>>> del p.x
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "<stdin>", line 7, in __delattr__
AttributeError: Not allowed

__getattr__(), __getattribute__() - 属性アクセスで呼び出される

>>> class Point:
...   pass
...
>>> p = Point()
>>> p.__dict__
{}
# p.__dict__['x'] = 1 に変換される
>>> p.x = 1
>>> p.__dict__
{'x': 1}
# __dict__は直接書き込み可能
>>> p.__dict__['y'] = 2
>>> p.y
2


イテラブルなオブジェクトとして振る舞う

__iter()__ - イテレータオブジェクトを返す。

■for i in x
for文はxの__iter__()を呼び出し、その戻り値を利用します
>>> class Iterable:
...   def __init__(self, num):
...     self.num = num
...   def __iter__(self):
...     return iter(range(self.num))
...
>>> [val for val in Iterable(3)]
[0, 1, 2]

 __next__() - 次の要素を返す。

■イテレータ
特殊メソッドの__iter__()と__next__()を実装したオブジェクトのこと。
>>> class Reverser:
...   def __init__(self, x):
...     self.x = x
...   def __iter__(self):
...     return self
...   def __next__(self):
...     try:
...       return self.x.pop()
...     except IndexError:
...       raise StopIteration()
...
>>> [val for val in Reverser([1, 2, 3])]
[3, 2, 1]

イテラブルとイテレータの違い

・イテラブル
 __iter__()を実装したオブジェクト
 __iter__()の戻り値は任意のイテレータ
・イテレータ
 __iter__()と__next__()を実装したオブジェクト
 __iter__()の戻り値は自分自身(self)


コンテナオブジェクトとして振る舞う

■コンテナオブジェクト(以下、コンテナ)
リストやタプル、辞書などほかのオブジェクトへの参照を持つオブジェクトです。

__getitem__(), __setItem__() - インデックスやキーによる操作

>>> from collections import defaultdict
>>> class CountDict:
...   def __init__(self):
...     self._data = {}
...     self._get_count = defaultdict(int)
...     self._set_count = defaultdict(int)
...   def __getitem__(self, key):
...     # c['x'] など参照時に呼ばれる
...     self._get_count[key] += 1
...     return self._data[key]
...   def __setitem__(self, key, value):
...     # c['x'] = 1 など代入時に呼ばれる
...     self._set_count[key] += 1
...     self._data[key] = value
...   @property
...   def count(self):
...     return {
...       'set': list(self._set_count.items()),
...       'get': list(self._get_count.items()),
...     }
...
>>> c = CountDict()
>>> c['x'] = 1
>>> c['x']
1
>>> c['x'] = 2
>>> c['y'] = 3

# 参照、代入された回数を返す
>>> c.count
{'set': [('x', 2), ('y', 1)], 'get': [('x', 1)]}

__contains__() - オブジェクトの有無を判定

>>> class OddNumbers:
...   def __contains__(self, item):
...     try:
...       return item % 2 == 1
...     except:
...       return False
...
>>> odds = OddNumbers()
>>> 1 in odds
True
>>> 4 in odds
False


まとめ

久々にPythonを利用すると、特殊メソッドを忘れることが多かったので、最低限知らないと他人のコードが読めないよって部分を抑えることができたので、非常に感謝です。

Pythonをメインに利用してる人って、この特殊メソッドの利用がうまいんだろうなーー。。。Python力を上げるためにも自分も利用しようと思いました。

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?