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__()
代わりに使ってる身としては耳が痛い。