Python組み込み関数7 -isinstance・issubclass編-
Pythonおさらい第7段
制約として公式ドキュメントのみ参照*1として、読む癖をつける訓練も兼ねる。
今回はisinstance関数
とissubclass関数
の2種類について。
前回に引き続き、特定の条件を満たすかどうか判定し、bool
を返す関数。
重要な関数ではあるものの、True
かFalse
が返るだけなので実に地味!
とはいえ、よく使うのは間違いないのでしっかり押さえておきたい。
読み込むドキュメントはこちら[isinstance, issubclass]
構成
今回の関数は以下のようになっている。
isinstance(object, classinfo)
issubclass(class, classinfo)
classinfo
とはなんぞや?
ドキュメントを読んでみると、型オブジェクト
, 型オブジェクトのタプル
あるいは再帰的に複数のタプル
だそうだが……再帰的に複数のタプルとはなんぞや?
謎は深まるばかりであるが使ってみた段階でわかることに期待したい。
関数 | 内容 |
---|---|
isinstance | object がclassinfo のインスタンスかどうか |
issubclass | class がclassinfo のサブクラスかどうかクラスはそれ自身のサブクラスとみなされる |
使ってみる
ひとまず、普通に単体のクラスで試してみて、classinfo
については専用の項目で見ていくこととする。
また、クラス定義などの共通部分については前提コードを使いまわす。
使ってみる-前提コード
from abc import ABC, abstractmethod class Creature(ABC): def __init__(self): self.alive = True @abstractmethod def desperate(self): pass def death(self): self.desperate() self.alive = False class Runner(ABC): def run(self): print(f'{self}は走った!') class Person(Creature): def __init__(self, name: str, age: int): self.name = name self.age = age super().__init__() def __repr__(self) -> str: me = f'{self.name}({self.age})' return me class Man(Person): def desperate(self): print(f'{self}: グワーッ!') class Woman(Person): def desperate(self): print(f'{self}: キャーッ!') class RunningMan(Runner, Man): pass man = Man('Otsuhachi', 28) rman = RunningMan('Taro', 55) woman = Woman('Hanako', 20) check_classes = [ABC, Creature, Person, Man, Woman, Runner, RunningMan] member = [man, rman, woman]
どうしようもないクソコードが爆誕してしまった……。
クラスの繋がりは以下の通り。
ABC ├ Creature │ └ Person │ ├ Woman │ └ Man │ ├─ RunningMan └───────── Runner
使ってみる-isinstance
前提コードで定義したmember
とcheck_classes
それぞれの組み合わせでisinstance
を行い、その結果を出力する。
実行するコードは以下の通り。
# ここより上の行に前提コードがある for m in member: print(f'{m}<{type(m).__name__}>') print('-' * 30) for cc in check_classes: print(f'{cc.__name__}: {isinstance(m,cc)}') print()
Otsuhachi(28)<Man> ------------------------------ ABC: True Creature: True Person: True Man: True Woman: False Runner: False RunningMan: False Taro(55)<RunningMan> ------------------------------ ABC: True Creature: True Person: True Man: True Woman: False Runner: True RunningMan: True Hanako(20)<Woman> ------------------------------ ABC: True Creature: True Person: True Man: False Woman: True Runner: False RunningMan: False
子クラスのインスタンスが親クラスをclassinfo
としてisinstance
したときにはTrue
が返っているのがわかる。
例えばman
はABC
->Creature
->Person
->Man
という繋がりを持つ、Man
クラスのインスタンスなので、classinfo
がABC
, Creature
, Person
, Man
のいずれでもTrue
となっている。
逆に同じ親クラスを持つWoman
は直接継承関係にないのでFalse
になるし、
Man
クラスの子クラスであるRunningMan
もFalse
となる。
object
のクラスが、どこかの段階でclassinfo
クラスを継承しているかを調べる関数だということが理解できた。
使ってみる-issubclass
check_classes[i]
がcheck_classes[j]
のサブクラスであるかを調べて出力する。
0 <= i,j < len(check_classes)
実行するコードは以下の通り。
# ここより上の行に前提コードがある for subcls in check_classes: print(subcls.__name__) print('-' * 30) for cls in check_classes: print(f'{cls.__name__}: {issubclass(subcls,cls)}') print()
ABC ------------------------------ ABC: True Creature: False Person: False Man: False Woman: False Runner: False RunningMan: False Creature ------------------------------ ABC: True Creature: True Person: False Man: False Woman: False Runner: False RunningMan: False Person ------------------------------ ABC: True Creature: True Person: True Man: False Woman: False Runner: False RunningMan: False Man ------------------------------ ABC: True Creature: True Person: True Man: True Woman: False Runner: False RunningMan: False Woman ------------------------------ ABC: True Creature: True Person: True Man: False Woman: True Runner: False RunningMan: False Runner ------------------------------ ABC: True Creature: False Person: False Man: False Woman: False Runner: True RunningMan: False RunningMan ------------------------------ ABC: True Creature: True Person: True Man: True Woman: False Runner: True RunningMan: True
自身と、自身のクラスが継承しているクラスがclassinfo
の場合True
が返るのがわかる。
isinstance
と違うのは第一引数がclass
な点くらいだろうか……。
メタプログラミングとかの際には必要になるのかもしれないが、今のところisinstance
ほど魅力を感じない。
使ってみる-classinfo
2つの関数共通の第二引数であるclassinfo
について。
受け取る形式は以下の3通り。
型オブジェクト
型オブジェクトのタプル
再帰的に複数の型オブジェクトのタプル
1.
, 2.
についてはわかりやすいのでさらっと以下のコードで確かめる。
# ここより上の行に前提コードがある classinfo = [str, (str, Runner)] for m in member: print(f'{m}<{type(m).__name__}>') print('-' * 30) for ci in classinfo: if type(ci) is tuple: c_name = tuple(map(lambda x: x.__name__, ci)) else: c_name = ci.__name__ print(f'{c_name}: {isinstance(m,ci)}') print()
Otsuhachi(28)<Man> ------------------------------ str: False ('str', 'Runner'): False Taro(55)<RunningMan> ------------------------------ str: False ('str', 'Runner'): True Hanako(20)<Woman> ------------------------------ str: False ('str', 'Runner'): False
型オブジェクトのタプルを渡した場合、いずれかのクラスがTrue
を返せばTrue
を返しているのがわかる。
以下のようなイメージすればわかりやすいだろう。
def tupled_isinstance(object, classinfo: tuple) -> bool: for ci in classinfo: if isinstance(object, ci): return True return False
問題なのは3.
だが、再帰的に複数のタプルとはなんなのか?
確信はないが、入れ子構造のタプルであると思われる。
以下のコードで確認してみる。
# ここより上の行に前提コードがある def convert_classnames(ct: tuple): res = [] for c in ct: if type(c) is tuple: res.append(convert_classnames(c)) else: res.append(c.__name__) return tuple(res) classinfo = [(str, Man), (str, (Woman, (Runner, RunningMan)))] for m in member: print(f'{m}<{type(m).__name__}>') print('-' * 60) for ci in classinfo: c_name = convert_classnames(ci) print(f'{c_name}: {isinstance(m,ci)}') print()
Otsuhachi(28)<Man> ------------------------------------------------------------ ('str', 'Man'): True ('str', ('Woman', ('Runner', 'RunningMan'))): False Taro(55)<RunningMan> ------------------------------------------------------------ ('str', 'Man'): True ('str', ('Woman', ('Runner', 'RunningMan'))): True Hanako(20)<Woman> ------------------------------------------------------------ ('str', 'Man'): False ('str', ('Woman', ('Runner', 'RunningMan'))): True
これが正しい再帰的に複数のタプル
であるかはわからないが、入れ子構造のタプルを渡した場合も問題なく判定していることは分かった。
締め
今回の2つの関数についてはクラスの継承
がどんなものか、インスタンスとクラスオブジェクトの違い
の2点がなんとなくでもわかっていれば、問題なく使うことができるだろう。
時々やらかすのが、classinfo
にインスタンスを指定してしまうことぐらいだろうか。
タプルの再帰に気を遣うぐらいならclassinfo
がインスタンスの時にtype(instance)
してくれる方がよほどありがたく感じる。
タプルはともかく、再帰的なタプルは本当にわからん。
*1:わかりやすく解説している他サイトを見ない
Python組み込み関数6 -bool・callable・hasattr編-
Pythonおさらい第6段
制約として公式ドキュメントのみ参照*1として、読む癖をつける訓練も兼ねる。
今回はbool関数
, callable関数
, hasattr関数
の3種類について。
isinstance
, issubclass
もbool
を返すという点では似ているが、次回に回す。
読み込むドキュメントはこちら[bool, callable, hasattr]
構成
今回の関数は以下のようになっている。
bool([x])
callable(object)
hasattr(object, name)
ドキュメントによると、それぞれ以下の項目を調べ、bool型
を返す。
関数 | 引数 | 判定する内容 |
---|---|---|
bool | __bool__() を持つクラスおよびそのインスタンス |
クラス定義の真偽値 |
callable | オブジェクト | オブジェクトが呼び出し可能かどうか |
hasattr | オブジェクト, 名前 | オブジェクトがその名前の属性を持つかどうか |
主にif文
などで使用し、例外を投げたり処理を分岐させる際に活用する関数とみて間違いないだろう。
hasattr(x)
は以下のようなコードとほぼ等価らしい。
def hasattr(object, name): try: getattr(object, name) return True except AttributeError: return False
使ってみる
使ってみる-bool
int型
の-28
,-1
,0
,1
,28
をそれぞれ判定してみるstr型
の' '
,''
,'\n'
,'\t'
,'Otsuhachi'
をそれぞれ判定してみる- 自作クラス
Person
を定義して判定してみる*2
実行するコードは以下の通り。
class Person: def __init__(self, name: str, age: int): self.name = name self.age = age def __repr__(self) -> str: me = f'{self.name}({self.age})' return me def __bool__(self) -> bool: return self.age >= 20 def check(data: list): if not data: msg = f'引数を1つ以上与える必要があります。' raise ValueError(msg) if len(set(type(x) for x in data)) != 1: msg = 'dataは同じ型で統一されている必要があります' raise TypeError(msg) t = type(data[0]).__name__ print(t) print('-' * 30) for d in data: print(f'"{d}": {bool(d)}') data = [ [-28, -1, 0, 1, 28], [' ', '', '\n', '\t', 'Otsuhachi'], [Person('Otsuhachi', 28), Person('Yamaki', 19)], ] for d in data: check(d) print()
int ------------------------------ "-28": True "-1": True "0": False "1": True "28": True str ------------------------------ " ": True "": False " ": True " ": True "Otsuhachi": True Person ------------------------------ "Otsuhachi(28)": True "Yamaki(19)": False
int型
は0
がFalse
でそれ以外はTrue
を返すようだ。
str型
は空文字がFalse
でそれ以外はエスケープシーケンス
であっても空白
であってもTrue
を返すようだ。
自作クラスPerson
では未成年をFalse
とし、成人をTrue
とする定義通りの結果が返っていることがわかる。
使ってみる-callable
int
,0
,str
,''
をそれぞれ判定してみる- 自作クラス
Person
のクラス、インスタンスをそれぞれ判定してみる Person
を継承し、__call__()
を定義したPerson2
のクラス、インスタンスをそれぞれ判定してみる
実行するコードは以下の通り。
class Person: def __init__(self, name: str, age: int): self.name = name self.age = age def __repr__(self) -> str: me = f'{self.name}({self.age})' return me class Person2(Person): def __call__(self, other): text = f'{repr(self)}: {"{}"}' if isinstance(other, Person): text = text.format(f'こんにちは、{other.name}') else: text = text.format(f'{type(other).__name__}型の{other}か') print(text) def check(data: list): if not data: msg = f'引数を1つ以上与える必要があります。' raise ValueError(msg) for d in data: print(f'{d}<{type(d).__name__}>: {callable(d)}') p1 = Person('Otsuhachi', 28) p2 = Person2('Yamaki', 19) data = [int, 0, str, '', Person, p1, Person2, p2] check(data)
<class 'int'><type>: True 0<int>: False <class 'str'><type>: True <str>: False <class '__main__.Person'><type>: True Otsuhachi(28)<Person>: False <class '__main__.Person2'><type>: True Yamaki(19)<Person2>: True
結果をまとめると以下の通りになっている。
オブジェクトの種類 | 結果 |
---|---|
クラスオブジェクト | True |
インスタンス(__call__() あり) |
True |
インスタンス(__call__() なし) |
False |
callable(x)
がTrue
を返すようなx
は、x(*args, **kwargs)
という式を実行可能であるということがわかる。
使い方-hasattr
- 自作クラス
Person
のクラス、インスタンスに対し、以下の属性名を確認するname
age
birthday
gender
実行するコードは以下の通り。
class Person: name: str age: int = 0 def __init__(self, name: str, age: int, birthday: str): self.name = name self.age = age self.birthday = birthday def __repr__(self) -> str: me = f'{self.name}({self.age})' return me p = Person('Otsuhachi', 28, '1995/06/04') t = Person.__name__ for attr in ('name', 'age', 'birthday', 'gender'): print(f'{attr}') print('-' * 30) print(f'{t}: {hasattr(Person,attr)}') print(f'{p}: {hasattr(p,attr)}') print()
name ------------------------------ Person: False Otsuhachi(28): True age ------------------------------ Person: True Otsuhachi(28): True birthday ------------------------------ Person: False Otsuhachi(28): True gender ------------------------------ Person: False Otsuhachi(28): False
Person
に対し、hasattr
した結果、型ヒントだけ与えた属性name
はFalse
で、代入を終えた属性age
はTrue
を返した。
また、Person
から生成したインスタンスではname
, age
に加え、クラス属性では触れていないbirthday
に関してもTrue
を返すようになった。
このことから、__init__()
内のself.birthday = birthday
の時点で、属性が追加されているのがわかる。
当然、クラス定義段階でもインスタンス生成段階でも触れなかった属性gender
については常にFalse
が返った。
個人的にはこう書きたい
Pythonのバージョンが進み、:=
演算子が使えるようになった今、
hasattr
で属性を確認したあと、その属性に用があるのなら以下のように書き換えてもいいかもしれない。
書き換え前
name = 'otsuhachi' attr_name = 'capitalize' if hasattr(name, attr_name): aft_name = getattr(name, attr_name)() print(name, '->', aft_name)
書き換え後
name = 'otsuhachi' attr_name = 'capitalize' if (attr := getattr(name, attr_name, None)) is not None: aft_name = attr() print(name, '->', aft_name)
結果はどちらもotsuhachi -> Otsuhachi
となる。
もちろん、特定の属性を持つか持たないかがわかればいいだけなら、hasattr
を使うべきだ。
締め
今回、真偽値を判定する関数3種類を紹介した。
引数のチェックが必要だったり、特定の属性を持つクラスのみの挙動を設定したりと使いどころは多いはずなので、なるべく早く慣れてしまいたい。
Python組み込み関数5 -bin・hex・oct編-
Pythonおさらい第5段
制約として公式ドキュメントのみ参照*1として、読む癖をつける訓練も兼ねる。
今回はbin関数
とoct関数
とhex関数
について。*2
それぞれ整数を2, 8, 16
進数表現の文字列に変換する関数である。
今回読み込むドキュメントはこちら[bin, oct, hex]
構成
今回の関数は以下のようになっている。
bin(x)
oct(x)
hex(x)
ドキュメントによると、それぞれ以下のように変換されるらしい。
整数を先頭に特定の文字列をつけた上でn進数
表現の文字列に変換する。
結果はPythonの式としても使える形式になる。
関数 | 先頭の文字列 | N進数 |
---|---|---|
bin | 0b | 2 |
oct | 0o | 8 |
hex | 0x | 16 |
使ってみる
どういうわけかhex
の説明にだけ*3、整数を返す__index__()
を定義したら使えるとある。
- 正の整数でそれぞれ試す
- 負の整数でそれぞれ試す
- 自作クラス
Person
で以下を試す__index__()
を定義したIdxPerson
を定義してそれぞれ試す__int__()
を定義したIntPerson
を定義してそれぞれ試す。
実行するコードは以下の通り。
class Person: def __init__(self, name: str, age: int): self.name = name self.age = age def __repr__(self) -> str: return f'{self.name}({self.age})' class IdxPerson(Person): def __index__(self): return id(self) class IntPerson(Person): def __int__(self): return self.age def show_boh(number): print(number) print('-' * 70) for name, f in zip(('bin', 'oct', 'hex'), (bin, oct, hex)): print(f'{name}: {f(number)}') tests = [ 1930, -1930, IdxPerson('__index__', 28), IntPerson('__int__', 28), ] for test in tests: try: show_boh(test) finally: print()
1930 ---------------------------------------------------------------------- bin: 0b11110001010 oct: 0o3612 hex: 0x78a -1930 ---------------------------------------------------------------------- bin: -0b11110001010 oct: -0o3612 hex: -0x78a __index__(28) ---------------------------------------------------------------------- bin: 0b101010111101010100000100010001111111010000 oct: 0o52752404217720 hex: 0x2af54111fd0 __int__(28) ---------------------------------------------------------------------- Traceback (most recent call last): ... TypeError: 'IntPerson' object cannot be interpreted as an integer
ドキュメントではhex
のみだったが、bin
, oct
でも問題なく__index__()
を定義することで使用できるようだ。
整数を返せればいいのかと、__int__()
だけ定義したIntPerson
ではこれらを使用できないこともわかった。
続いてPythonの式として使用してみる。
文字列を返す関数を式に……というのがいまいちピンとこないが、ひとまず以下のコードを実行してみる。
print(bin(18) + bin(10))
0b100100b1010
この結果はシンプルに2つの文字列を連結しただけのようだ。
この時点で勘違いに気付く。
Pythonの式として使える形式というのは、文字が混ざっていても数値として解釈されるということだったらしい。
以下のコードを実行してみる。
print(0b10010 + 0b1010) print(type(0b10010))
28 int
2進数表現で18+10
の計算を行い、その結果を出力しているので、出力は28
と正しい値を返した。
また、型名を調べる関数を使用した結果からもint型
として扱われているのがわかった。
締め
今回は整数を2, 8, 16
進数表現の文字列として取得する方法と、2, 8, 16
進数表現でint型
を扱う方法が理解できた。
前者はbin, oct, hex
関数を使わずにformat関数
や文字列に変数を埋め込む書式などでも代用可能らしいが、それらについてはformat関数
で触れることにする。覚えていれば
Python組み込み関数4 -ascii・repr・str編-
Pythonおさらい第4弾
制約として公式ドキュメントのみ参照*1として、読む癖をつける訓練も兼ねる。
今回はascii関数
とrepr関数
、さらにstr関数
について。
知ってる関数で似通ったものはできる限りまとめていきたい。
普段使うのはrepr
とstr
で、ascii
についてはよく知らない。
読み込むドキュメントはこちら[ascii, repr, str]
構成
今回の関数は以下のようになっている。
ascii(object)
repr(object)
str(object='')
str(object=b'', encoding='utf-8', errors='strict')
ascii
ドキュメントによると、ascii
はrepr
と同様にオブジェクトの印字可能な表現を含む文字列を返すが、非ASCII文字はエスケープされるらしい。
Python2
のrepr
と等価。
repr
repr
はオブジェクトの印字可能な表現を含む文字列を返し、その文字列は主に以下のようなものになるらしい。
また、自作クラスでは__repr__()
を定義することでこの関数で返す文字列を制御することができる。*2
eval関数
に渡されたときと同じ値を持つようなオブジェクト表す文字列- 山括弧に囲まれたオブジェクトの型の名前と追加の情報*3
str
str
はobject
のみを受け取るものとキーワード引数encoding
, errors
を指定するものが存在しているらしい。
object
のみのものは、object
の文字列版を返すが、object
が空の場合は空文字が返る。
自作クラスの場合では__str__()
を定義することでこの関数で返す文字列を制御することができる。*4
__str__()
を持たないクラスはrepr
の結果と等価。
キーワード引数encoding
, errors
の少なくとも一方が与えられた場合のstr
についての説明は現時点ではよくわからないが、object
がbyte-like object
である必要があり、bytes.decode(encoding, errors)
と等価になるらしい。
今回のおさらいでは割愛。
使ってみる
以下の説明のそれぞれ試す
とはascii
, repr
, str
での出力を試みることである。
__repr__()
も__str__()
も定義しない自作クラスPerson
でそれぞれ試すPerson
を継承し、__repr__()
を定義したRPerson
でそれぞれ試すPerson
を継承し、__str__()
を定義したSPerson
でそれぞれ試すRPerson
,SPerson
を継承したRSPerson
でそれぞれ試す
実行するコードは以下の通り。
from typing import Iterable class Person: def __init__(self, name: str, age: int): self.name = name self.age = age class RPerson(Person): def __repr__(self) -> str: me = f'{self.name}({self.age})' return me class SPerson(Person): def __str__(self) -> str: me = f'{self.name}、{self.age}歳です!' return me class RSPerson(RPerson, SPerson): pass def show_person(persons: Iterable): for i, person in enumerate(persons): if i: print() print(type(person).__name__) print('-' * 55) print(f'repr: {repr(person)}') print(f'ascii: {ascii(person)}') print(f'str: {str(person)}') me = {'name': 'Otsuhachi', 'age': 28} persons = [p(**me) for p in (Person, RPerson, SPerson, RSPerson)] show_person(persons)
Person ------------------------------------------------------- repr: <__main__.Person object at 0x0000028225D32A60> ascii: <__main__.Person object at 0x0000028225D32A60> str: <__main__.Person object at 0x0000028225D32A60> RPerson ------------------------------------------------------- repr: Otsuhachi(28) ascii: Otsuhachi(28) str: Otsuhachi(28) SPerson ------------------------------------------------------- repr: <__main__.SPerson object at 0x0000028225D32820> ascii: <__main__.SPerson object at 0x0000028225D32820> str: Otsuhachi、28歳です! RSPerson ------------------------------------------------------- repr: Otsuhachi(28) ascii: Otsuhachi(28) str: Otsuhachi、28歳です!
表にまとめると以下のようになる。
関数 | 未定義 | reprのみ | strのみ | 両方 |
---|---|---|---|---|
repr | <__main__.Person object at 0x0000028225D32A60> | Otsuhachi(28) | <__main__.Person object at 0x0000028225D32A60> | Otsuhachi(28) |
ascii | <__main__.Person object at 0x0000028225D32A60> | Otsuhachi(28) | <__main__.Person object at 0x0000028225D32A60> | Otsuhachi(28) |
str | <__main__.Person object at 0x0000028225D32A60> | Otsuhachi(28) | Otsuhachi、28歳です! | Otsuhachi、28歳です! |
__repr__()
も__str__()
も定義していない場合に出力される文字列はすべてのクラスのスーパークラスであるobject
の__repr__()
である。
__str__()
が定義されていない場合、__repr__()
の結果が返るが、その逆は発生しないことがわかる。
asciiについては残念ながらこの例では出力の差異を見ることができなかった。
締め
今回、str関数
に2種類あることがわかったが、現状ではascii
のありがたい使い道についてはわからなかった。
__repr__()
はevel関数
で等価なオブジェクトを生成できるものが好ましいという点も記憶の片隅にとどめておいた方がいいかもしれない。
eval関数
はセキュリティリスクが面倒くさそうだからそもそもあまり使いたくないイメージ。
__str__()
は人にやさしい出力を定義する慣習があるっぽい。
リストの中身が直接見れないからって__repr__()
を__str__()
代わりに使ってる身としては耳が痛い。
Python組み込み関数3 -all・any編-
Pythonおさらい第3段
制約として公式ドキュメントのみ参照*1として、読む癖をつける訓練も兼ねる。
今回はall関数
とany関数
の2種類について。
ブログのレイアウト弄りをしていたとはいえ、日数が空いたうえでのこの薄さ……まずい。
all
はイテラブルの中身がすべてTrue
かどうか。
any
はイテラブルの中身のいずれかがTrue
かどうか。
残念ながらこれ以上の情報はこの記事から得られないので、どう水増しするか気になる人以外は解散!お疲れ様でした!
構成
今回の2つの関数は共通項が多いので同時に紹介していく。
all(iterable)
any(iterable)
ドキュメントによると、それぞれ以下のようなコードと等価です。
# all def all(iterable): for element in iterable: if not element: return False return True # any def any(iterable): for element in iterable: if element: return True return False
使ってみる
- 自作クラス
Person
を定義して、名簿member
を作成 member
に対しall
,any
をそれぞれ使用してその出力を見る
実行するコードは以下の通り。
class Person: def __init__(self, name: str, age: int): self.name = name self.age = age def __bool__(self): print(f'Check {self.name}: {self.age}') return self.age >= 20 member = [ Person('Otsuhachi', 28), Person('Taro', 18), Person('Jiro', 20), Person('Hanako', 14), ] print('All') print(all(member), '\n') print('Filterd') print(all(filter(lambda x: x.age >= 20, member))) print('-' * 30) print('Any') print(any(member), '\n') print('Filterd') print(any(filter(lambda x: x.age < 20, member)))
All Check Otsuhachi: 28 Check Taro: 18 False Filterd Check Otsuhachi: 28 Check Jiro: 20 True ------------------------------ Any Check Otsuhachi: 28 True Filterd Check Taro: 18 Check Hanako: 14 False
今回、Person
クラスでは成人をTrue
、未成年をFalse
と定義している。
all
を使用した結果、Taro
がFalse
を返した時点でFalse
が返されているのがわかる。
つぎにfilter(lambda x: x.age >= 20, member)
を使用して、all
に渡すメンバーから未成年を除外すると、成人であるOtsuhachi
とJiro
がチェックされ、True
が返った。
any
を使用した結果、Otsuhachi
がTrue
を返した時点でTrue
が返されているのがわかる。
つぎにfilter(lambda x: x.age < 20, member)
を使用してany
に渡すメンバーから成人を除外した結果、未成年であるTaro
とHanako
がチェックされ、False
が返った。
締め
ネタとしては極めて薄い関数ながら、コードの短縮という意味ではなかなかにありがたい関数だと思われる。
*1:わかりやすく解説している他サイトを見ない
Index -プログラミング-
Python
組み込み関数
A
B
C
D
- delattr
- dict
- dir
- divmod
E
- enumerate
- eval
- exec
F
- filter
- float
- format
- frozenset
G
- getattr
- globals
H
I
- id
- import
- input
- int
- isinstance
- issubclass
- iter
L
- len
- list
- locals
M
- map
- max
- memoryview
- min
N
- next
O
P
- pow
- property
R
- range
- repr
- reversed
- round
S
- set
- setattr
- slice
- sorted
- staticmethod
- str
- sum
- super
T
- tuple
- type
V
- vars
Z
- zip
Python組み込み関数2 -abs編-
Pythonおさらい第2弾
制約として公式ドキュメントのみ参照*1として、読む癖をつける訓練も兼ねる。
今回はabs関数
について。
前回結構頑張ったので今回は緩く済ませられそうな関数をチョイス。
いわゆる絶対値を返す関数としてしか認識していないが実態はいかに……。
読み込むドキュメントはこちら
構成
abs関数
の詳細はこんな感じ。
abs(x)
ドキュメントによると、数値の絶対値を返すとのこと。
int
, float
, complex
に加えて__abs__()
を実装しているオブジェクトに対応するそう。
以上!
認識が一切覆ることなく、でしょうねという感想しか出てこない。
使ってみる
int型
の-10
,0
,10
に対し使用float型
の-10.1
,-0.1
,0.0
,0.1
,10.01
に対し使用
実行するコードは以下の通り。
def show_abs(text, list_): print(text) print('-' * 30) for i in list_: print(f'abs({i}): {abs(i)}') int_list = [-10, 0, 10] float_list = [-10.1, -0.1, 0.0, 0.1, 10.01] show_abs('int型', int_list) print() show_abs('float型', float_list)
int型 ------------------------------ abs(-10): 10 abs(0): 0 abs(10): 10 float型 ------------------------------ abs(-10.1): 10.1 abs(-0.1): 0.1 abs(0.0): 0.0 abs(0.1): 0.1 abs(10.01): 10.01
当然な結果。
自作クラス
さすがにあんまりなので自作クラスに__abs__()
を定義して使ってみることにする。
complex
は複素数型らしいが、学がないのでそもそも複素数が何かわからんです。
実行するコードとその出力は以下の通り。
class Person: def __init__(self, name: str, age: int): self.name = name self.age = age def __int__(self) -> int: return self.age def __str__(self) -> str: me = f'{self.name}({self.age})' return me def __abs__(self) -> int: return id(self) me = Person('Otsuhachi', 28) print(me, int(me), abs(me), sep='\n')
Otsuhachi(28) 28 2523203087376
abs(me)
で返るのは今回実行時のme
のIDなので、プログラム終了までは一定で、実行毎に変動する値になる。
無事、絶対値を取得できる自作クラスを作成できた。
締め
今回は特別学ぶことはなかった印象。
__abs__()
を実装すれば自作クラスでも動くとはいえ、現状ではあまり用途が思いつかない。
組み込み関数コンプリートのために書いた感が拭えない結果となった。
これからもif x < 0: x *= -1
を省略するためにしか使わなそう。
*1:わかりやすく解説している他サイトを見ない