
Python チュートリアルを読んで気になったところをメモ。
str と repr の違い
よくある疑問なんだと思うけど、自分用に整理。
基本的には、どちらも様々な型のデータを文字列に変換するための関数です。で、どういうときにどっちを使うのか?
- repr(obj)
- 開発者向けの文字列を出力する
- 原則として
eval(repr(obj)) == objが成り立つように設計されている - デバッグやログで
eval()評価の結果の値を「正確な情報」として知ることができる
- str(obj)
- ユーザー向けの文字列表現
- 通常のフォーマットとして出力される
実際の話だと repr() を、ユーザーが str() ほど直接的に利用するのかというと、そこまで多いわけではないと思います。利用回数が多くなるのは、おそらく str() になるのが殆どのケースのはず。(基本的に repr は representation = 「表示」の意味のはずです)
個人的な用途のポイントとしては 改行文字 が含まれる可能性のある文字列は repr() を使って、出力やデバッグしたほうがよいケースはあると思う。もちろん、改行したほうが読みやすいケースもあったり、文字列だと '' で括られたりもする癖は eval() の都合だと思うけど開発用途だと留意は必要。
s = "hello\nworld" print(s) print(repr(s)) # 'hello\nworld'
内部的に利用されているケースが考えられるけど、その内部的な動きを意識しないと困るケースは少ないと思う。
また、ライブラリを作るときに __repr__ を定義しておく必要があるかというと C# の [DebuggerDisplay] 属性を付ける必要があるかどうかと、考え方は似ていると思う。(ベストプラクティスとしては、どちらもセットで実装するべき)
class Sample: def __init__(self, id, name): self.id = id self.name = name def __repr__(self): return f"<Sample id={self.id}, name='{self.name}'>" def __str__(self): return f"{self.name} (#{self.id})" # テストコード s = Sample(1, "Alice") print(s) print(repr(s))
Alice (#1) <Sample id=1, name='Alice'>
基本的にはデバッグの操作をやりやすくするための機能として repr() を使用する。
出力フォーマット
以下の変数をフォーマット化して出力する公式の例ですが、「-」を付ける意味がよくわからなかったので確認したが、結局、意味ないように思う。
yes_votes = -42_572_654 total_votes = 85_705_149 percentage = yes_votes / total_votes a = '{:-12} YES votes {:2.2%}'.format(yes_votes, percentage) b = '{:12} YES votes {:2.2%}'.format(yes_votes, percentage) print(a) print(b)
-42572654 YES votes -49.67% -42572654 YES votes -49.67%
この例は、負数のときだけ「-」を付けることを明示しているけど、実際的な話として出力結果に差はない。ただし「+」の場合は違いがある。
yes_votes = 42_572_654 total_votes = 85_705_149 percentage = yes_votes / total_votes a = '{:+12} YES votes {:2.2%}'.format(yes_votes, percentage) b = '{:12} YES votes {:2.2%}'.format(yes_votes, percentage) print(a) print(b)
+42572654 YES votes 49.67%
42572654 YES votes 49.67%
これは sign に説明してあるとおり - はデフォルトの振る舞いなので付ける意味が特にない。その一方で + はデフォルトでは付かない。また C# の出力のように正数・負数・ゼロをまとめてフォーマットを処理できるわけでもない。
int pos = 42;
int neg = -42;
int zero = 0;
Console.WriteLine("{0:#;(#);Zero}", pos); // "42"
Console.WriteLine("{0:#;(#);Zero}", neg); // "(42)"
Console.WriteLine("{0:#;(#);Zero}", zero); // "Zero"
なので python で書式に - をつけるのは、本当にただの冗長的な意味しかないと思う。(下記のように負数の場合にのみ記号を付けてる、という説明になっているけど、サンプルは正数だし、負数に記号がつくのはデフォルトの動作だし、ちょっと微妙な内容ではないかと思う)
Notice how the
yes_votesare padded with spaces and a negative sign only for negative numbers.
クラス
名前とオブジェクトについての整理。python は C# のように「変数の中に値が入る」というイメージではない。その逆で、「オブジェクト(値)」があって、それに「名前(ラベル)」を貼り付けしているイメージになる。
基本的に、この考えかただと C# の参照型と同じようなイメージを持つことになると思う。(文中でもポインタについて言及があるけど)
ただし、基本的な型である数値 int や、文字列 str は immutable なオブジェクトのタイプで、ラベルに新しいオブジェクトを割り当てる動きになる。
a = 10 b = a # b は a と同じオブジェクトを指す b = 20 # b に別の数を代入すると、b に新しいオブジェクトを割り当てるだけ print(a) # 10 (a は変わらず 10 のオブジェクトが割り当たっている)
一方で list だと以下のようになる。変数の考え方は C# と python でちょっと違う点は注意しないといけない。
a = [1,2,3] b = a # b は a と同じオブジェクトを指す b.append(4) # b が割り当たっているオブジェクトに 4 を追加 print(a) # [1,2,3,4] (a が割り当たっているオブジェクトは b と同じ)
で、最後に「これにより、 Pascal にあるような二つの引数渡し機構をもつ必要をなくしています。」という文で締められるけど、具体的には値渡し (call by value) と参照渡し (call by reference) のことですよね。
C# の例
// 値渡し
void Foo(int x) { x = 100; }
int a = 10;
Foo(a);
Console.WriteLine(a); // 10
// 参照渡し
void Foo(ref int x) { x = 100; }
int a = 10;
Foo(ref a);
Console.WriteLine(a); // 100
python の場合は、繰り返しだけど、「オブジェクト(値)」があって、それに「名前(ラベル)」を貼り付けしているイメージをする。この例では参照渡しのように動作するが a ラベルが指し示すオブジェクトを x として渡して、同じオブジェクトに 100 を append している。
def foo(x): x.append(100) a = [1, 2, 3] foo(a) print(a) # [1,2,3,100]
スコープと名前空間について
名前を解決するときは次の順番:
python の変数スコープの概念として LEGB rule として知られているみたいです。参照する変数を変更する際は global や nonlocal などを変数名に指定することで、書き換えるオブジェクトを切り替えることができる。
x = "global" def outer(): x = "enclosing" def inner(): x = "local" print(x) inner() outer()
built-in は、最初から python に入っている名前空間をいいます。なので len() や print() は組み込み関数なので built-in です。
import を使用したときの場合だと、例えば import math は global に追加される。モジュールレベルのスコープになるので built-in ではない。
import しなくても使える機能ということなので、重要度は高いものが(当然だけど)多いです。
import builtins print(dir(builtins))
私の環境(のひとつ)では、以下の出力でした。この内容を整理しておきます。
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BaseExceptionGroup', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EncodingWarning', 'EnvironmentError', 'Exception', 'ExceptionGroup', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'aiter', 'all', 'anext', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
出力結果を整理します:
基底クラス
- BaseException
- Exception
- BaseExceptionGroup
- ExceptionGroup
よく使うエラー
- ArithmeticError
- AssertionError
- AttributeError
- BufferError
- EOFError
- FloatingPointError
- IndentationError
- ImportError
- IndexError
- KeyError
- LookupError
- MemoryError
- NameError
- NotImplementedError
- OSError
- OverflowError
- RecursionError
- ReferenceError
- RuntimeError
- SyntaxError
- SystemError
- TabError
- TimeoutError
- TypeError
- UnboundLocalError
- UnicodeDecodeError
- UnicodeEncodeError
- UnicodeTranslateError
- UnicodeError
- ValueError
- WindowsError
- ZeroDivisionError
OS/ IO 関連エラー
- BlockingIOError
- BrokenPipeError
- ChildProcessError
- ConnectionError(接続エラーの基底)
- ConnectionAbortedError
- ConnectionRefusedError
- ConnectionResetError
- EnvironmentError
- FileExistsError
- FileNotFoundError
- IOError
- InterruptedError
- IsADirectoryError
- ModuleNotFoundError
- NotADirectoryError
- PermissionError
- ProcessLookupError
制御フロー用の特殊な例外
- GeneratorExit
- KeyboardInterrupt
- StopAsyncIteration
- StopIteration
- SystemExit
Warning 関係
- BytesWarning
- DeprecationWarning
- EncodingWarning
- FutureWarning
- ImportWarning
- PendingDeprecationWarning
- ResourceWarning
- RuntimeWarning
- SyntaxWarning
- UnicodeWarning
- UserWarning
- Warning
定数
- Ellipsis(
...) - False
- None
- NotImplemented
- True
double underscore
dunder = double undersocre 一覧:
__build_class____debug__- true または false を持つ組み込み定数
- 最適化モード (
-Oオプション)で false になる(通常は true になる)
__doc__- オブジェクトの docstring に入る属性
__import__- import 文の実体
- 普段は直接使わないが python が import 文の内部でこれを使う
__loader__- モジュールが import されたときにつかわれた loader object
- どの方法でモジュールを load したのかが格納される
- 通常は import をカスタマイズしたいときだけなので触らない
__name__- モジュールの名前が入る特別な変数
- スクリプトとして直接実行された場合は
"__name__"になる
__package__- モジュールが属するパッケージの名前
from . import xxxxのような相対 import に使ってるので、直接は触らない
__spec__- モジュールの import 情報(ModuleSpec)が入る
- どのファイルから load されたのか、などのメタ情報
- 使うとしてもツールを作る側
関数
| 名前 | 概要 |
|---|---|
abs(x) |
絶対値を返す |
aiter(obj) |
非同期イテレータを返す |
all(iterable) |
すべて真なら true |
anext(async_iterator, default) |
非同期イテレータで次の要素を返す |
any(iterable) |
いずれか真なら true |
ascii(obj) |
非 ascii 文字をエスケープ文字に変換 |
bin(x) |
整数を2進数の文字列に変換 |
bool(x) |
真理値に変換(0, '', None = false) |
breakpoint() |
デバッガを起動 |
bytearray(source) |
可変バイト列型に変換 |
bytes(source) |
不変バイト列型に変換 |
callable(obj) |
呼び出し可能なら true |
chr(i) |
unicode コードポイントから文字を返却(int to str) |
classmethod(func) |
クラスメソッド化するデコレータ |
compile(source, filename, mode) |
ソースをコードオブジェクトにコンパイル |
complex(real, imag) |
複素数を生成 |
copyright |
著作権表示文字列を表示 |
credit |
謝辞文字列を表示 |
delattr(obj, name) |
obj.name 属性を削除 |
dict(...) |
辞書型を作成 |
dir(obj) |
属性リストを返却 |
divmod(a, b) |
a // b, a % b の tuple を返却 |
enumerate(iterable, start=0) |
インデックス付きのイテレータを返す |
eval(expr, globals, locals) |
文字列を式として評価 |
exec(object, globals, locals) |
文字列やコードオブジェクトを実行 |
exit |
対話環境で終了するためのオブジェクト = quit |
filter(func, iterable) |
条件にあう要素だけ取り出すイテレータ |
float(x) |
浮動小数点の数に変換 |
format(value, format_spec) |
文字列をフォーマット |
frozenset(iterable) |
不変集合型。set と違い要素変更不可 |
getattr(obj, name, default) |
obj.name を動的に取得 |
globals() |
グローバル名前空間の dict を返却 |
hasattr(obj, name) |
属性が存在すれば true |
hash(obj) |
オブジェクトのハッシュ値を返却 |
help(obj) |
ヘルプのシステムを起動 |
hex(i) |
整数を16進数の文字列に変換 |
id(obj) |
オブジェクトの一意な ID |
input(prompt) |
標準入力から文字列を取得する |
int(x, base) |
整数に変換(基数を指定できる) |
isinstance(obj, class_or_tuple) |
オブジェクトがその型かどうかをチェック |
issubclass(cls, class_or_tuple) |
クラスがそのサブクラスかどうかをチェック |
iter(obj, sentinel) |
イテレータを返却 |
len(obj) |
要素数を返却 |
license |
ライセンスを表示 |
list(iterable) |
リストを生成 |
locals() |
ローカル名前空間の dict を返却 |
map(func, iterable, ...) |
各要素に関数を適用するイテレータ |
max(iterable, *) |
最大値を返す |
memoryview(obj) |
バイト列のメモリビューを返却 |
min(iterable, *) |
最小値を返す |
next(iterator, default) |
イテレータから次の要素を返す |
object |
すべてのクラスの基底 |
oct(x) |
整数を8進数文字列に変換 |
open(file, mode='r', ...) |
ファイルを開く |
ord(c) |
文字の unicode コードポイントを返却 |
pow(x, y, mod) |
x**y(mod の指定で累乗剰余) |
print(*args, sep=' ', end='\n') |
標準出力に表示 |
property(fget, fset, fdel, doc) |
プロパティを作成するでスクリプタ |
quit |
対話環境を終了 = exit |
range(start, stop, step) |
数列イテレータを返却 |
repr(obj) |
obj の文字列表現を返却 |
reversed(seq) |
逆順のイテレータを返却 |
round(number, ndigits) |
四捨五入 |
set |
集合を生成 |
setattr(obj, name, value) |
属性を設定 |
slice(stop) |
スライスオブジェクトを生成(文字列のスライス) |
sorted(iterable, *) |
ソートしたリストを返却 |
staticmethod(func) |
静的メソッド化するデコレータ |
str(obj) |
文字列に変換 |
sum(iterable, start=0) |
数値の合計を返却 |
super(type, obj) |
親クラスのメソッドを呼び出す |
tuple(iterable) |
tuple を生成 |
type(obj) |
オブジェクトの型を返却 |
vars(obj) |
オブジェクトの __dict__ を返す |
zip(*iterables) |
複数のイテラブルをまとめる |