プログラミング FAQ¶
一般的な質問¶
ブレークポイントやステップ実行ができる、ソースコードレベルのデバッガはありますか?¶
はい。
Python 用のデバッガについては次に解説してあり、組み込みの breakpoint() 関数でそれらのデバッガに処理を移せます。
pdb モジュールは簡素にして十分な Python のコンソールモードデバッガです。これは Python の標準ライブラリに含まれているもので、 ライブラリリファレンスマニュアルにドキュメントがあります 。 pdb のコードを手本にして自分用のデバッガを書くこともできます。
IDLE 対話型開発環境は、標準 Python ディストリビューションの一部 (普通は idlelib として利用可能) であり、グラフィカルなデバッガを含んでいます。
PythonWin は、pdb をベースとした GUI デバッガを含む Python IDE です。Pythonwin デバッガは、ブレークポイントの色付けや非 PythonWin プログラムのデバッグなどの素敵な機能をたくさん持っています。PythonWin は pywin32 プロジェクトの一部、あるいは ActivePython ディストリビューションの一部として利用可能です。
Eric は PyQt や Scintilla editing component をもとにした IDE です。
trepan3k は gdbライクなデバッガです。
Visual Studio Code はバージョン管理ソフトと一緒になったデバッグツールを備えた IDE です
商業のグラフィカルデバッガ付き Python IDE もあります。例えば:
バグの発見や静的解析に役立つツールはありますか?¶
はい。
Ruff, Pylint と Pyflakes は、基本的なチェックを行いバグの早期発見を助けます。
mypy, ty, Pyrefly, そして pytype などの静的型チェッカーは、 Python ソースコードにある型ヒントをチェックできます。
どうしたら Python スクリプトからスタンドアロンバイナリを作れますか?¶
ユーザがダウンロードでき、Python ディストリビューションをインストールせずに実行できるようなスタンドアロンプログラムだけでいいなら、Python を C コードにコンパイルできなくても構いません。プログラムに対して必要なモジュールを選び、そのモジュールを Python バイナリに束縛して一つの実行可能ファイルにまとめる多くのツールがあります。
ひとつは freeze ツールを使うことですが、これはPython ソースツリーに Tools/freeze として含まれています。これは Python バイトコードを C 配列に変換します。併せて C コンパイラを使うと あなたの全モジュールを新しいプログラムに埋め込み、それを Python 標準モジュールにリンクすることができます。
これはあなたのソースの (両方の形式の) import 文を再帰的にスキャンし、import されたモジュールを標準の Python パスと (組み込みモジュールのある) ソースディレクトリから探します。そして Python で書かれたモジュールのバイトコードを C コード (marshal モジュールでコードオブジェクトに変換できる配列) に変換し、実際にそのプログラム内で使われている組み込みモジュールだけが含まれたカスタムメイドの設定ファイルを作成します。そして生成された C コードをコンパイルして Python インタプリタの残りとリンクし、元のスクリプトと全く同じように動作する自己完結的なバイナリを形成します。
以下のパッケージはコンソールやGUIの実行ファイル作成に役立ちます。
Nuitka (Cross-platform)
PyInstaller (Cross-platform)
PyOxidizer (Cross-platform)
cx_Freeze (Cross-platform)
py2app (macOS only)
py2exe (Windows only)
Python プログラムのためのコーディングスタンダードやスタイルガイドはありますか?¶
はい。標準ライブラリモジュールに求められるコーディングスタイルは PEP 8 として文書化されています。
コア言語¶
なぜ変数に値があるのに UnboundLocalError が出るのですか?¶
もともと動いていたコードが、関数の本体のどこかに代入文を加えるという変更をしたら UnboundLocalError を出すのには驚くかもしれません。
このコード:
>>> x = 10
>>> def bar():
... print(x)
...
>>> bar()
10
は動きますが、このコード:
>>> x = 10
>>> def foo():
... print(x)
... x += 1
は UnboundLocalError になります:
>>> foo()
Traceback (most recent call last):
...
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
これは、あるスコープの中で変数に代入を行うとき、その変数はそのスコープに対してローカルになり、外のスコープにある同じ名前の変数を隠すからです。foo の最後の文が x に新しい値を代入しているので、コンパイラはこれをローカル変数であると認識します。その結果、先の print(x) が初期化されていないローカル変数を表示しようとして結果はエラーとなります。
上の例では、グローバルであると宣言することで外のスコープにアクセスできます:
>>> x = 10
>>> def foobar():
... global x
... print(x)
... x += 1
...
>>> foobar()
10
この明示的な宣言は (表面的には似ているクラスとインスタンス変数の例とは違って) あなたは実際は他のスコープの変数の値を変えようとしているのだ、ということを知らせるのに必要です:
>>> print(x)
11
同様のことを、ネストされたスコープで nonlocal 予約語を使うことでもできます:
>>> def foo():
... x = 10
... def bar():
... nonlocal x
... print(x)
... x += 1
... bar()
... print(x)
...
>>> foo()
10
11
Python のローカルとグローバル変数のルールは何ですか?¶
Python では、関数内で参照されるだけの変数は暗黙的にグローバルとなります。 関数の本体のどこかで値が変数に代入されたなら、それは明示的にグローバルであると宣言されない限り、ローカルであるとみなされます。
最初はちょっと驚くでしょうが、少し考えると納得できます。一方では、代入された変数に global を要求することで、意図しない副作用を防げます。他方では、グローバルな参照の度に global が要求されてしまうと、 global を使ってばかりになってしまいます。ビルトイン関数やインポートされたモジュールの内容を参照するたびにグローバル宣言をしなければならないのです。その乱雑さは副作用を特定するための global 宣言の便利さよりも重大です。
ループの中で異なる値で定義されたラムダ式が、同じ値を返すのはなぜですか?¶
for ループを使って、少しずつ異なるラムダを定義 (もしくは簡単な関数) するとします。例えば:
>>> squares = []
>>> for x in range(5):
... squares.append(lambda: x**2)
これで x**2 を計算する 5 つのラムダのリストが得られます。それらを呼び出したとき、それぞれ 0、1、4、9、16 を返すと予想するかもしれません。しかし実際にやってみると、全て 16 が返ってくるのを目にするでしょう:
>>> squares[2]()
16
>>> squares[4]()
16
これは、x がラムダにとってのローカル変数ではなく外側のスコープで定義されていて、ラムダが定義されたときでなく呼び出されたときにアクセスされるために起こります。ループが終わった時点では x は 4 であり、従って、全ての関数は 4**2 つまり 16 を返します。このことは x の値を変えてみることで検証でき、ラムダの返り値がどのように変わるのか観察できます:
>>> x = 8
>>> squares[2]()
64
これを避けるためには、グローバルの x の値に依存しないために、ラムダにとってのローカル変数に値を保存する必要があります:
>>> squares = []
>>> for x in range(5):
... squares.append(lambda n=x: n**2)
ここで、n=x は新しいラムダにとってのローカル変数 n を作成し、ラムダが定義されるときに計算されるので、ループのその時点での x と同じ値を持っています。これは、1 つ目のラムダでは n の値は 0 になり、2 つ目では 1、3 つ目では 2 以下同様、となることを意味します。従って、それぞれのラムダは今や正しい値を返すようになりました:
>>> squares[2]()
4
>>> squares[4]()
16
この動作はラムダに特有なものではなく、通常の関数にも適用されることに注意してください。
モジュールで import を使う際の「ベストプラクティス」は何ですか?¶
一般的に from modulename import * を使ってはいけません。そのようにするとインポータの名前空間は汚染され、linter が未定義の名前を発見することが難しくなります。
モジュールはファイルの先頭でインポートしてください。これによってコードが必要とする他のモジュールが明確になり、モジュール名がスコープに含まれるかどうかに迷わなくなります。行に一つのインポートにすると、モジュールのインポートの追加と削除が容易になりますが、行に複数のインポートにすると画面の領域が少なく済みます。
次の手順でモジュールをインポートするのが、良い習慣になります:
サードパーティのライブラリモジュール (Python の site-packages ディレクトリにインストールされているもの) -- 例 dateutil, requests, tzdata
自前で開発したモジュール
循環インポートの問題を避けるために、インポートを関数やクラスに移すことが必要なときもあります。 Gordon McMillan によれば:
循環インポートは両方のモジュールが "import <module>" 形式のインポートを使っていれば大丈夫です。 二つ目のモジュールが最初のモジュールから名前を確保しようとして ("from module import name")、そのインポートがトップレベルにあると駄目です。 最初のモジュールが二つ目のモジュールをインポートするのに忙しくて、最初のモジュールの名前が利用可能になっていないからです。
この状況では、二つ目のモジュールが一つの関数の中でのみ使われているならば、そのインポートは簡単に関数の中に移せます。インポートが呼ばれたとき、最初のモジュールは初期化を完了していて、二つ目のモジュールは自分のインポートをできます。
プラットフォーム依存のモジュールがあるときには、インポートをトップレベルの外に動かすことも必要です。この場合、ファイルの先頭ではすべてのモジュールをインポートすることさえできないかもしれません。この場合は、対応するプラットフォームに合わせたコードで正しいモジュールをインポートすることを選ぶと良いです。
インポートを関数定義内などのローカルスコープへ移すのは、循環インポートを避けるといった問題の解決に必要な場合や、モジュールの初期化時間を短くしたい場合だけにしてください。
この手法は、プログラムの実行のされ方によって多くのインポートが不要になる場合に特に有効です。
モジュールをある関数の中でしか使わない場合も、インポートをその関数内へ移すとよいでしょう。
初回の読み込みにはモジュールの初期化が伴うため、時間がかかることがあります。
一方、繰り返し読み込むときのコストは辞書を数回検索する程度で、ほぼ無視できます。
モジュール名がスコープから外れても、モジュール自体はおそらく sys.modules に残っています。
オプションパラメータやキーワードパラメータを関数から関数へ渡すにはどうしたらいいですか?¶
関数のパラメータリストに引数を * と ** 指定子 (specifier) で集めてください。そうすれば、位置引数をタプルとして、キーワード引数を辞書として得られます。これで、他の関数を呼び出すときに * と ** を使ってそれらの引数を渡せます:
def f(x, *args, **kwargs):
...
kwargs['width'] = '14.3c'
...
g(x, *args, **kwargs)
実引数と仮引数の違いは何ですか?¶
仮引数 (parameter) は関数定義に表れる名前で定義されるのに対し、 実引数 (argument) は関数を呼び出すときに実際に渡す値のことです。 仮引数は関数が受け取ることの出来る 実引数の種類 を定義します。 例えば、以下のような関数定義があったとして:
def func(foo, bar=None, **kwargs):
pass
foo、bar、kwargs は func の仮引数です。一方、func を呼び出すときには、例えば:
func(42, bar=314, extra=somevar)
42、314、somevar という値は実引数です。
なぜ list 'y' を変更すると list 'x' も変更されるのですか?¶
次のようなコードを書いたとします:
>>> x = []
>>> y = x
>>> y.append(10)
>>> y
[10]
>>> x
[10]
どうして y への要素の追加が x も変更してしまうのか疑問に思うかもしれません。
このような結果になる2つの要因があります:
変数とは、単にオブジェクトを参照するための名前に過ぎません。
y = xとすることは、リストのコピーを作りません -- それはxが参照するのと同じオブジェクトを参照する新しい変数yを作ります。つまり、あるのは一つのオブジェクト(この場合リスト)だけであって、xとyの両方がそれを参照しているのです。リストは mutable です。内容を変更出来る、ということです。
append() 呼び出しの後、ミュータブルオブジェクトの内容が [] から [10] に変わります。 変数が同じオブジェクトを参照しているので、どちらの名前であっても変更された値 [10] にアクセスします。
代わりに x にイミュータブルを代入すると:
>>> x = 5 # int はイミュータブル(不変)
>>> y = x
>>> x = x + 1 # 5 は変更不可。 ここでは新しいオブジェクトを作っている
>>> x
6
>>> y
5
この場合ご覧の通り x と y はまったく同じではありませんね。これは整数が immutable だからで、 x = x + 1 は整数の 5 の値を変更しているのではありません; 代わりに新しいオブジェクト(整数 6)を作って x に代入しています (つまり x が参照するオブジェクトが変わります)。この代入の後では私たちは 2 つのオブジェクト(整数の 6 と 5)を持っていて、2 つの変数はそれらを参照しています(x はいまや 6 を参照していますが y は 5 を参照したままです)。
ある演算 (たとえば y.append(10), y.sort()) がオブジェクトを変更する一方で、外見上は似た演算 (たとえば y = y + [10], sorted(y)) は新しいオブジェクトを作ります。Python では一般に (そして標準ライブラリの全てのケースで)、このような 2 つのタイプの演算にまつわる混乱を避けるために、オブジェクトを変更するメソッドは None を返します。ですからもしあなたが誤って y の複製の並び替えをするつもりで y.sort() と書いた場合に結果手にするのは None でしょうから、あなたのプログラムは簡単に診断出来るエラーを起こすでしょう。
しかしながら、同じ操作が型ごとに異なる振る舞いをする演算の種類が一つあります: 累算代入演算です。例えば += はリストを変更しますが、タプルや整数は変更しません(a_list += [1, 2, 3] は a_list.extend([1, 2, 3]) と同じ意味で、そして a_list を変更しますが、 some_tuple += (1, 2, 3) と some_int += 1 は新しいオブジェクトを作ります)。
言い換えると:
出力引数のある関数 (参照渡し) はどのように書きますか?¶
Pythonにおける実引数は代入にて渡されることと留意してください。 代入はオブジェクトへの参照を作るだけなので、呼び出し元/先での引数名の間にエイリアスは存在せず、従って参照渡しになりません。 目的の動作を実現するには、いくつか方法があります。
結果のタプルを返すことによって:
>>> def func1(a, b): ... a = 'new-value' # a と b はローカル名で ... b = b + 1 # 新しいオブジェクトが代入され ... return a, b # 新しい値一式を返す ... >>> x, y = 'old-value', 99 >>> func1(x, y) ('new-value', 100)
これはたいてい一番明確な方法です。
グローバル変数を使って。これはスレッドセーフでないので、推奨されません。
ミュータブルな (インプレースに変更可能な) オブジェクトを渡すことによって:
>>> def func2(a): ... a[0] = 'new-value' # 'a' は mutable list への参照 ... a[1] = a[1] + 1 # 共有されたオブジェクトを変える ... >>> args = ['old-value', 99] >>> func2(args) >>> args ['new-value', 100]
変更を受ける辞書を渡すことによって:
>>> def func3(args): ... args['a'] = 'new-value' # args は mutable dictionary ... args['b'] = args['b'] + 1 # インプレースで変更 ... >>> args = {'a': 'old-value', 'b': 99} >>> func3(args) >>> args {'a': 'new-value', 'b': 100}
または、クラスインスタンスに値を同梱することによって:
>>> class Namespace: ... def __init__(self, /, **args): ... for key, value in args.items(): ... setattr(self, key, value) ... >>> def func4(args): ... args.a = 'new-value' # args は mutable Namespace ... args.b = args.b + 1 # オブジェクトをインプレースで変更 ... >>> args = Namespace(a='old-value', b=99) >>> func4(args) >>> vars(args) {'a': 'new-value', 'b': 100}
このような複雑なことをする理由はめったに無いでしょう。
一番の選択は、複数の結果を含むタプルを返すことです。
Python で高次関数はどのようにつくりますか?¶
二つの方法があります: ネストされたスコープを使う方法と、呼び出し可能オブジェクトを使う方法です。例えば、a*x+b の値を計算する f(x) 関数を返す linear(a,b) を定義したいとします。ネストされたスコープを使うと:
def linear(a, b):
def result(x):
return a * x + b
return result
また、呼び出し可能オブジェクトを使うと:
class linear:
def __init__(self, a, b):
self.a, self.b = a, b
def __call__(self, x):
return self.a * x + self.b
どちらの場合でも、
taxes = linear(0.3, 2)
とすれば、taxes(10e6) == 0.3 * 10e6 + 2 となるような呼び出し可能オブジェクトを得られます。
呼び出し可能オブジェクトを使う方法は、少し遅くなり、わずかにコードが長くなるという短所があります。ですが、継承を使って呼び出し可能オブジェクト同士でシグネチャを共有することもできます:
class exponential(linear):
# __init__ 継承
def __call__(self, x):
return self.a * (x ** self.b)
オブジェクトは複数メソッド向けの状態をカプセル化できます:
class counter:
value = 0
def set(self, x):
self.value = x
def up(self):
self.value = self.value + 1
def down(self):
self.value = self.value - 1
count = counter()
inc, dec, reset = count.up, count.down, count.set
ここで、inc()、dec()、reset() は同じカウント変数を共有する関数のようにふるまいます。
Python のオブジェクトはどのようにコピーしますか?¶
一般的に、普通は copy.copy() や copy.deepcopy() を試してください。何でもコピーできるとは限りませんが、たいていはできます。
もっと簡単にコピーできるオブジェクトもあります。辞書には copy() メソッドがあります:
newdict = olddict.copy()
シーケンスはスライシングでコピーできます:
new_l = l[:]
オブジェクトのメソッドや属性はどのように見つけますか?¶
ユーザー定義クラスのインスタンス x で、dir(x),< はインスタンス属性とそのクラスで定義されたメソッドや属性を含む名前のアルファベット順リストを返します。
どうすればコードにてオブジェクトの名前を得ることができますか?¶
一般的に言えば、できません。なぜならオブジェクトは実は名前を持ちません。本質的には、いつでも代入とは値に名前を束縛することです。def と class 文も同じですが、この場合の値はコーラブルです。以下のコードを考えてみましょう:
>>> class A:
... pass
...
>>> B = A
>>> a = B()
>>> b = a
>>> print(b)
<__main__.A object at 0x16D07CC>
>>> print(a)
<__main__.A object at 0x16D07CC>
おそらく、このクラスには名前があります。このクラスは二つの名前に縛られて、名前 B を通して呼び出されますが、それでもクラス A のインスタンスとして報告されるのです。しかし、両方の名前が同じ値に束縛されている以上、このインスタンスの名前が a か b か決めることはできないのです。
概して、コードにとってある値の「名前を知っている」事は重要ではありません。あなたがあえて introspective (訳注:実行時のオブジェクト情報を調査するような)プログラムを書いているのでない限り、方針を変えた方がいいかもしれないということになるでしょう。
comp.lang.python で、Fredrik Lundh はこの問題の答えとして素晴らしい喩えをしてくれました:
玄関にいた猫の名前を知るのと同じ方法です: その猫 (オブジェクト) 自体はその名前を言うことができないし、それは実は問題ではありません -- その猫が何と呼ばれているかを知る唯一の方法は、すべての隣人 (名前空間) にその猫 (オブジェクト) が何と呼ばれているかを聞くことです。
……そして、その猫が沢山の名前で知られていたり、逆に全く名前が無かったりしても驚かないでください!
カンマ演算子の優先順位はどうなっていますか?¶
カンマは Python では演算子ではありません。このセッションを考えてください:
>>> "a" in "b", "a"
(False, 'a')
カンマは演算子ではなく、式の分離子なので、上の式は次の式と同じように評価されます:
("a" in "b"), "a"
こうではありません:
"a" in ("b", "a")
他のさまざまな演算子(=、+= など)も同じです。これらは真の演算子ではありませんが、代入文の構文上のデリミタです。
C の "?:" 三項演算子と等価なものはありますか?¶
はい、あります。構文は以下のようになります:
[on_true] if [expression] else [on_false]
x, y = 50, 25
small = x if x < y else y
この構文が導入された 2.5 以前のバージョンに関しては、論理演算子を使ったこのイディオムが一般的でした:
[expression] and [on_true] or [on_false]
しかし、このイディオムは安全ではありません。on_true のブール値が偽であるときに間違った結果を与えることがあります。ですから、いつでも ... if ... else ... 形式を使ったほうが良いです。
Python で解し難いワンライナーを書くことはできますか?¶
はい。そういうものはたいてい、 lambda の中に lambda がネストされています。Ulf Bartelt によるものを少しアレンジした下の3つの例を見てください:
from functools import reduce
# 素数 < 1000
print(list(filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,
map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))
# 先頭 10 フィボナッチ数列
print(list(map(lambda x,f=lambda x,f:(f(x-1,f)+f(x-2,f)) if x>1 else 1:
f(x,f), range(10))))
# マンデルブロ集合
print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y,
Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,
Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,
i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y
>=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(
64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy
))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24))
# \___ ___/ \___ ___/ | | |__ 画面行数
# V V | |______ 画面列数
# | | |__________ 最大 "iterations"
# | |_________________ y 軸範囲
# |____________________________ x 軸範囲
よい子はまねしないでね!
関数の仮引数リストにあるスラッシュ (/) は何を意味しますか?¶
関数の仮引数にあるスラッシュは、それより前にある仮引数は位置専用引数であることを示します。
位置専用引数は、外から使える名前を持たない仮引数です。
位置専用引数を受け付ける関数の呼び出しにおいて、実引数はその位置だけに基づいて仮引数に対応付けられます。
例えば、 divmod() は位置専用引数を受け付けます。
そのドキュメントは次のようになります:
>>> help(divmod)
Help on built-in function divmod in module builtins:
divmod(x, y, /)
Return the tuple (x//y, x%y). Invariant: div*y + mod == x.
この引数リストの末尾にスラッシュは、この2つの仮引数が両方とも位置専用引数であることを意味します。
したがって、divmod() をキーワード引数を使って呼び出すとエラーになります:
>>> divmod(x=3, y=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: divmod() takes no keyword arguments
数と文字列¶
十六進数や八進数を指定するにはどうしたらいいですか?¶
八進数を指定するには、八進数での値の先頭に 0 と "o" (小文字または大文字) を加えてください。たとえば、変数 "a" に八進数での "10" (十進数での"8") を代入するには、こう打ってください:
>>> a = 0o10
>>> a
8
十六進数も簡単です。ただ十六進数での値の先頭に 0 と "x" (小文字または大文字) を加えてください。十六進数は小文字でも大文字でも指定できます。たとえば、Python インタプリタで:
>>> a = 0xa5
>>> a
165
>>> b = 0XB2
>>> b
178
なぜ -22 // 10 は -3 を返すのですか?¶
i % j が j と同じ符号であってほしいことに基づいています。それに加えて以下のようにもしたいとすると:
i == (i // j) * j + (i % j)
整数除算は床、つまり商以下の最大の整数を返す必要があります。
C でもこの等式を満たす必要があり、商をゼロ方向に切り捨てるコンパイラでは、i % j の符号を i と同じにする必要があります。
i % j は、j が負の時には実際にはほとんど使いません。j が正なら、たくさん使います。その事実上すべての場合、i % j は >= 0 となる方が便利です。時計が 10 時を指している時、その 200 時間前は何時でしょうか。-190 % 12 == 2 となるのが便利です。-190 % 12 == -10 は噛み付きかねないバグです。
どうすれば SyntaxError を起こさずに整数リテラルの属性を得られますか?¶
ふつうの方法で int リテラルの属性を探そうとすると、ピリオドが小数点とみなされ、SyntaxError となります:
>>> 1.__class__
File "<stdin>", line 1
1.__class__
^
SyntaxError: invalid decimal literal
解決策は、リテラルとピリオドを スペースや括弧で分けることです。
>>> 1 .__class__
<class 'int'>
>>> (1).__class__
<class 'int'>
文字列を数に変換するにはどうしたらいいですか?¶
整数に変換するには、組み込みの int() 型コンストラクタを使ってください。例えば、 int('144') == 144 です。同様に、 float() は浮動小数点に変換します。例えば、 float('144') == 144.0 です。
デフォルトでは、これらは数を十進数として解釈するので、 int('0144') == 144 は成立しますが int('0x144') は ValueError を送出します。 int(string, base) はオプションの第二引数をとって変換元の基数にします。つまり int( '0x144', 16) == 324 です。基数が 0 と指定された場合、その数は Python の基準によって解釈されます。先頭が '0o' なら八進数で、'0x' なら十六進数を表します。
文字列を数に変換するだけのために eval() を使わないでください。 eval() は特に遅いですし、セキュリティ上のリスクもあります。求められない副作用を持つような Python の式を渡そうとする人がいるかも知れません。例えば、あなたのホームディレクトリを消去する __import__('os').system("rm -rf $HOME") を渡そうとする人がいるかも知れません。
eval() は数を Python の式として解釈する効果もあるため、例えば、 eval('09') は構文エラー起こします。 Python は ('0' 以外の) 十進数を '0' で始めてはならないからです。
数を文字列に変換するにはどうしたらいいですか?¶
例えば、144 という数を '144' という文字列に変換したいなら、組み込み型のコンストラクタ str() を使ってください。
十六進数や八進数にしたければ、組み込み関数の hex() や oct() を使ってください。
手の込んだフォーマット形式を使うなら、 f-strings と 書式文字列の構文 の節を参照してください。
例えば、 "{:04d}".format(144) は '0144' になり、 "{:.3f}".format(1.0/3.0) は '0.333' になります。
文字列をインプレースに変更するにはどうしたらいいですか?¶
文字列はイミュータブルなので、それはできません。殆どの場合、組み立てたい個別の部品から単純に新しい文字列を構成するべきです。しかし、 Unicode データをインプレースに変更できるオブジェクトが必要なら、 io.StringIO オブジェクトや array モジュールを試してください:
>>> import io
>>> s = "Hello, world"
>>> sio = io.StringIO(s)
>>> sio.getvalue()
'Hello, world'
>>> sio.seek(7)
7
>>> sio.write("there!")
6
>>> sio.getvalue()
'Hello, there!'
>>> import array
>>> a = array.array('w', s)
>>> print(a)
array('w', 'Hello, world')
>>> a[0] = 'y'
>>> print(a)
array('w', 'yello, world')
>>> a.tounicode()
'yello, world'
関数やメソッドを呼ぶのに文字列を使うにはどうしたらいいですか?¶
様々なテクニックがあります。
一番いいのは、文字列を関数に対応させる辞書を使うことです。このテクニックの一番の利点は、文字列が関数の名前と同じ必要がないことです。この方法は case 構造をエミュレートするための一番のテクニックでもあります:
def a(): pass def b(): pass dispatch = {'go': a, 'stop': b} # 注意:関数にはカッコなし dispatch[get_input()]() # 注意:関数を呼び出すには末尾カッコ
組み込み関数の
getattr()を使う方法:import foo getattr(foo, 'bar')()
なお、
getattr()はクラス、クラスインスタンス、モジュールなど、どんなオブジェクトにも使えます。これは標準ライブラリでも何箇所か使われています。このように:
class Foo: def do_foo(self): ... def do_bar(self): ... f = getattr(foo_instance, 'do_' + opname) f()
locals()を使って関数名を決める方法:def myFunc(): print("hello") fname = "myFunc" f = locals()[fname] f()
文字列から後端の改行を取り除く Perl の chomp() に相当するものはありますか?¶
S.rstrip("\r\n") を使って文字列 S の終端から他の空白文字を取り除くことなくすべての行末記号を取り除くことができます。文字列 S が複数行を表し、終端に空行があるとき、そのすべての空行も取り除かれます:
>>> lines = ("line 1 \r\n"
... "\r\n"
... "\r\n")
>>> lines.rstrip("\n\r")
'line 1 '
これは典型的に一度に一行ずつテキストを読みたい時にのみ使われるので、S.rstrip() をこの方法で使うとうまくいきます。
scanf() や sscanf() に相当するものはありますか?¶
そのようなものはありません。
単純な入力を解析するには、通常、文字列オブジェクトの split() メソッドで行を空白区切りの単語に分割し、int() や float() で十進数の文字列を数値に変換するのが最も簡単です。
split() には省略可能な sep 引数があり、空白以外の区切り文字を使った行を扱うのに便利です。
もっと複雑な入力解析をしたいなら、C の sscanf よりも正規表現の方が便利ですし、この処理に向いています。
UnicodeDecodeError や UnicodeEncodeError は何を意味しますか?¶
Unicode HOWTO を参照して下さい。
raw string を奇数個のバックスラッシュで終えることはできますか?¶
奇数個のバックスラッシュで終わる raw string は文字列のクォートをエスケープします:
>>> r'C:\this\will\not\work\'
File "<stdin>", line 1
r'C:\this\will\not\work\'
^
SyntaxError: unterminated string literal (detected at line 1)
これにはいくつかの回避策があります。ひとつは通常文字列と二重バックスラッシュを使うことです:
>>> 'C:\\this\\will\\work\\'
'C:\\this\\will\\work\\'
もうひとつは、エスケープされたバックスラッシュを含む通常の文字列を、 raw string に連結します:
>>> r'C:\this\will\work' '\\'
'C:\\this\\will\\work\\'
Windowsでは、 os.path.join() を使ってバックスラッシュを追加することもできます:
>>> os.path.join(r'C:\this\will\work', '')
'C:\\this\\will\\work\\'
注意点として、バックスラッシュは raw string 終端のクォートを「エスケープ」しますが、 raw string の値を解釈する際にはエスケープが生じません。つまり、バックスラッシュは raw string 値の中に残ったままになります:
>>> r'backslash\'preserved'
"backslash\\'preserved"
言語リファレンス の仕様も参照してください。
性能¶
プログラムが遅すぎます。どうしたら速くなりますか?¶
一般には難しい問題です。 詳しく検討する前に、まず次の点を覚えておいてください。
性能の傾向は Python 実装によって変わります。この FAQ では CPython に焦点を当てます。
振る舞いはオペレーティングシステムによって変わりえます。特に、I/O やマルチスレッドに関しては顕著です。
常に、コードの最適化を始める 前に プログラムのホットスポットを見つけるべきです (
profileモジュールを参照してください)。ベンチマークスクリプトを書くことで、改善箇所の捜索を素早く繰り返せます (
timeitモジュールを参照してください)。洗練された最適化に隠れたリグレッションの可能性を生む前に、(ユニットテストやその他の技法で) コードカバレッジを上げることを強く推奨します。
とはいえ、Python コードを高速化する方法はたくさんあります。 満足できる性能を得るうえで大いに役立つ一般的な方針を紹介します。
コード中に細かい最適化の技法をばらまこうとするよりも、アルゴリズムを高速化 (または高速なアルゴリズムに変更) するほうが、大きな利益を生むことがあります。
適切なデータ構造を使ってください。組み込み型 や
collectionsを調べてください。何かをするための基本要素が標準ライブラリにあるなら、自分で発明した代用品よりもそちらのほうが、(絶対にとは言えませんが) おそらく速いです。 それが組み込み型やある種の拡張型のように C で書かれたものならなおさらです。 たとえば、ソートするには、必ず
list.sort()組み込みメソッドかsorted()関数を使ってください (また、中程度に高度な例は、 ソートのテクニック を参照してください)。抽象化によって処理が間接的になると、インタープリタの仕事が増えがちです。 間接的な処理の負担が本来の処理の量を上回ると、プログラムが遅くなります。 過度な抽象化、特に細かすぎる関数やメソッドは避けるべきです。 こうした関数やメソッドは、読みやすさを損なうこともよくあります。
Python だけで書いたコードの限界に達したら、さらに性能を上げるためのツールがあります。 例えば Cython は、Python コードに少し手を加えたものを C 拡張にコンパイルでき、多くのプラットフォームで使えます。 Cython はコンパイルと、省略可能な型アノテーションを活用することで、インタープリタによる実行よりもコードを大幅に高速化できます。 C のプログラミングに自信があれば、自分で C 拡張モジュールを書く こともできます。
参考
パフォーマンス tips が載っている wiki のページ。
多くの文字列を結合するのに最も効率的な方法は何ですか?¶
str と bytes のオブジェクトはイミュータブルなので、多数の文字列を連結すると、そのたびに新しいオブジェクトが作られて非効率になります。
一般には、実行時間は文字列の全長の二乗に比例します。
詳しくは 組み込み型の操作の時間計算量 を参照してください。
多くの str オブジェクトを累積するのにおすすめのイディオムは、すべてをリストに配置してから最後に str.join() を呼び出すことです:
chunks = []
for s in my_strings:
chunks.append(s)
result = ''.join(chunks)
(io.StringIO を使うのも、ある程度効率のよい方法です。)
多くの bytes オブジェクトを累積するのにおすすめのイディオムは、 bytearray オブジェクトをインプレース結合 (+= 演算子) で拡張することです:
result = bytearray()
for b in my_bytes_objects:
result += b
シーケンス (タプルとリスト)¶
タプル、リスト間の変更はどのようにするのですか?¶
型コンストラクタ tuple(seq) はすべてのシーケンス (実際には、すべてのイテラブル) を同じ要素、同じ順序のタプルに変換します。
例えば、 tuple([1, 2, 3]) は (1, 2, 3) を与え、 tuple('abc') は ('a', 'b', 'c') を与えます。引数がタプルなら、コピーを作らずに引数のオブジェクトそのものを返すので、あるオブジェクトが既にタプルになっているか確信が持てないのなら、 tuple() を呼ぶのが手軽です。
型コンストラクタ list(seq) はすべてのシーケンスあるいはイテラブルを同じ要素、同じ順序のリストに変換します。例えば、list((1, 2, 3)) は [1, 2, 3] を与え、list('abc') は ['a', 'b', 'c'] を与えます。引数がリストなら、seq[:] と同様にコピーを作ります。
負の添え字は何ですか?¶
Python のシーケンスは正の数と負の数でインデクスされます。正の数では、0 が最初のインデクス、1 が 2 番目のインデクス、以下も同様です。負のインデクスでは、-1 が最後のインデクス、-2 が最後から 2 番目のインデクス、以下も同様です。seq[-n] は seq[len(seq)-n] と同じだと考えてください。
負のインデクスを使うと便利なことがあります。例えば、S[:-1] は文字列の最後以外のすべての文字を表すので、文字列の末尾の改行を取り除くときに便利です。
シーケンスを逆順にイテレートするにはどうしたらいいですか?¶
組み込み関数 reversed() を使ってください。
for x in reversed(sequence):
... # x を使った処理 ...
これは元のシーケンスをいじるのではなく、逆順の新しいコピーを作ってイテレートさせます。
リストから重複を取り除くにはどうしますか?¶
Python Cookbook の長い議論に多くの方法があるので参照してください:
リストの順序を変えてもよければ、ソートしてから末尾から順に調べ、重複を削除してください。
if mylist:
mylist.sort()
last = mylist[-1]
for i in range(len(mylist)-2, -1, -1):
if last == mylist[i]:
del mylist[i]
else:
last = mylist[i]
リストのすべての要素を集合に格納できる場合 (つまり、すべてが hashable な場合) は、次の方法のほうが速いことがよくあります。
mylist = list(set(mylist))
リストを集合に変換するときに重複は取り除かれるので、それをリストに戻せばいいのです。
リストから複数の要素を取り除くにはどうしますか?¶
重複を取り除く場合と同じように、逆順にイテレートし、条件に合う要素を削除する方法があります。 ただし、暗黙的または明示的に順方向へイテレートし、スライスを置き換えるほうが簡単で高速です。 次の 3 通りの書き方があります。
mylist[:] = filter(keep_function, mylist)
mylist[:] = (x for x in mylist if keep_condition)
mylist[:] = [x for x in mylist if keep_condition]
リスト内包表記がおそらく最も高速です。
Python で配列を作るにはどうしますか?¶
リストを使ってください:
["this", 1, "is", "an", "array"]
リストの時間計算量は C や Pascal の配列と同じです。大きな違いは、Python のリストは多くの異なる型のオブジェクトを含めることです。
array モジュールにも、型を固定した配列をコンパクトな表現で作るためのメソッドがありますが、インデックスによるアクセスはリストより遅くなります。
また、NumPy などのサードパーティーパッケージも、さまざまな特性を持つ配列に似た構造を定義しています。
Lisp 方式の連結リストを得るのに、タプルを使って cons cells をエミュレートできます:
lisp_list = ("like", ("this", ("example", None) ) )
ミュータブルな必要があるなら、タプルではなくリストを使いましょう。Lisp の car にあたるものが lisp_list[0] で、cdr にあたるものが lisp_list[1] です。本当に必要だと確信できるとき以外はこれはしないでください。たいてい、これは Python のリストを使うよりも非常に遅いですから。
多次元のリストを作るにはどうしますか?¶
このようにして多次元の配列を作ろうとしてしまったことがあるでしょう:
>>> A = [[None] * 2] * 3
これを表示したときには問題なさそうに見えます:
>>> A
[[None, None], [None, None], [None, None]]
しかし値を代入すると、その値が複数の場所に現れてしまいます:
>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]
* によるリストの繰り返しは、要素のコピーではなく既存のオブジェクトへの参照を作るためです。
*3 は、長さ 2 の同じリストへの参照を 3 つ含むリストを作ります。
1 つの行を変更するとすべての行に反映されますが、これが意図した結果であることはまずないでしょう。
おすすめの方法は、最初に望んだ長さのリストを作り、それから新しく作ったリストでそれぞれの要素を埋めていくことです:
A = [None] * 3
for i in range(3):
A[i] = [None] * 2
これは長さ 2 の異なるリスト 3 つを含むリストを生成します。リスト内包表記も使えます:
w, h = 2, 3
A = [[None] * w for i in range(h)]
あるいは、行列データ型を提供している拡張を使用することもできます; NumPy が最もよく知られています。
オブジェクトのシーケンスにメソッドや関数を適用するにはどうしますか?¶
メソッドや関数を呼び出し、その戻り値をリストにまとめるには、list comprehension を使うと簡潔に書けます。
result = [obj.method() for obj in mylist]
result = [function(obj) for obj in mylist]
戻り値を保存せずにメソッドや関数を実行するだけなら、ただの for ループで十分です:
for obj in mylist:
obj.method()
for obj in mylist:
function(obj)
なぜ加算はされるのに a_tuple[i] += ['item'] は例外を送出するのですか?¶
これは、累算代入演算子は 代入 演算子だ、という事実と、Python での可変オブジェクトと不変オブジェクトの違いが組み合わさって起きるのです。
この議論は一般的に、可変オブジェクトを指すタプルの要素に、累算代入演算子が適用されたときにも適用できますが、例として list と += を使います。
次のように書いたとします:
>>> a_tuple = (1, 2)
>>> a_tuple[0] += 1
Traceback (most recent call last):
...
TypeError: 'tuple' object does not support item assignment
例外の理由は明らかでしょう。
a_tuple[0] が指すオブジェクト (1) に 1 を加えると、結果のオブジェクト 2 が作られます。
しかし、計算結果の 2 をタプルのインデックス 0 の要素に代入しようとするとエラーになります。
タプルの要素が指すオブジェクトは変更できないためです。
このような裏事情の元、累算代入文はだいたい次のようなことをしています:
>>> result = a_tuple[0] + 1
>>> a_tuple[0] = result
Traceback (most recent call last):
...
TypeError: 'tuple' object does not support item assignment
タプルは不変なので、例外を生み出しているのは操作の代入部分なのです。
次のように書いたとします:
>>> a_tuple = (['foo'], 'bar')
>>> a_tuple[0] += ['item']
Traceback (most recent call last):
...
TypeError: 'tuple' object does not support item assignment
この例外にはちょっと驚きますが、もっと驚くべきことは、エラーがあったとしても追記はきちんと動いている、という事実です:
>>> a_tuple[0]
['foo', 'item']
この理由を理解するには、次の 2 点を知る必要があります。
(a) オブジェクトに __iadd__() 特殊メソッドが実装されていると、+= による累算代入の実行時にそのメソッドが呼ばれ、戻り値が代入に使われます。
(b) リストの __iadd__() は、そのリストの extend() を呼び出してからリストを返すのと同じです。
このため、リストの += は list.extend() の「短縮形」といえます。
>>> a_list = []
>>> a_list += [1]
>>> a_list
[1]
これは次と等価です:
>>> result = a_list.__iadd__([1])
>>> a_list = result
a_list が指していたオブジェクトは更新され、更新されたオブジェクトへのポインタは再度 a_list に代入されます。代入しているのは、a_list が更新前まで指していた同じオブジェクトへのポインタなので、代入は最終的には何もしていないのですが、代入処理自体は起きています。
従って、今のタプルの例では、次のと同じことが起きています:
>>> result = a_tuple[0].__iadd__(['item'])
>>> a_tuple[0] = result
Traceback (most recent call last):
...
TypeError: 'tuple' object does not support item assignment
__iadd__() は成功し、リストは拡張 (extend) されますが、result が a_tuple[0] が既に指しているオブジェクトと同じオブジェクトを指していたとしても、タプルは不変なので、その最後の代入はやはりエラーとなります。
複雑なソートがしたいのですが、Python でシュワルツ変換はできますか?¶
Perl コミュニティの Randal Schwartz の作とされるこのテクニックは、リストの要素を、それぞれの要素をその「ソート値」に対応付けるメトリックによってソートします。Python では、 list.sort() メソッドに key 引数を使ってください:
Isorted = L[:]
Isorted.sort(key=lambda s: int(s[10:15]))
リストを別のリストの値によってソートするにはどうしますか?¶
2 つのリストをタプルのイテレータにまとめ、その結果から得られるリストをソートして、必要な要素を取り出してください。
>>> list1 = ["what", "I'm", "sorting", "by"]
>>> list2 = ["something", "else", "to", "sort"]
>>> pairs = zip(list1, list2)
>>> pairs = sorted(pairs)
>>> pairs
[("I'm", 'else'), ('by', 'sort'), ('sorting', 'to'), ('what', 'something')]
>>> result = [x[1] for x in pairs]
>>> result
['else', 'sort', 'to', 'something']
オブジェクト¶
クラスとは何ですか?¶
クラスは class 文の実行によって作られる、特定の種類のオブジェクトです。 クラスオブジェクトはインスタンスオブジェクトを作るためのテンプレートとして使われます。 インスタンスオブジェクトは、そのデータ型に固有のデータ (属性) とコード (メソッド) の両方を備えています。
新しいクラスを一つ以上の他のクラス (新しいクラスの基底クラスと呼ばれます) に基づいて作ることもできます。この新しいクラスは、基底クラスから属性とメソッドを継承します。これにより、オブジェクトモデルを継承で連続的に洗練できます。メールボックスへの基本的なアクセサを提供する一般的な Mailbox クラスを作って、それからいろいろな特定のメールボックスの形式を扱う MboxMailbox、MaildirMailbox、OutlookMailbox のようなサブクラスを作れるのです。
メソッドとは何ですか?¶
メソッドは、オブジェクト x が持つ関数で、通常 x.name(arguments...) として呼び出されるものです。メソッドはクラス定義の中で関数として定義されます:
class C:
def meth(self, arg):
return arg * 2 + self.attribute
self とは何ですか?¶
self はメソッドの第一引数に慣習的につけられる名前にすぎません。meth(self, a, b, c) として定義されたメソッドは、その定義がなされたクラスのインスタンス x に対して x.meth(a, b, c) として呼び出されます。呼び出されたメソッドは、meth(x, a, b, c) が呼ばれたものと考えます。
なぜメソッドの定義や呼び出しにおいて 'self' を明示しなければならないのですか? も参照してください。
あるオブジェクトが、与えられたクラスやそのサブクラスのインスタンスであるかを調べるにはどうしますか?¶
組み込み関数 isinstance(obj, cls) を使ってください。
isinstance(obj, (class1, class2, ...)) のように、クラスを 1 つ渡す代わりにタプルを渡すと、複数のクラスのいずれかのインスタンスであるかを調べられます。
また、isinstance(obj, str) や isinstance(obj, (int, float, complex)) のように、Python の組み込み型のインスタンスであるかも調べられます。
isinstance() は abstract base class の仮想的な継承も調べます。
そのため、抽象基底クラスに登録されたクラスであれば、直接または間接的に継承していなくても True を返します。
「実際の継承」を調べるには、そのクラスの method resolution order (MRO) を確認します。
from collections.abc import Mapping
class P:
pass
class C(P):
pass
Mapping.register(P)
>>> c = C()
>>> isinstance(c, C) # 直接
True
>>> isinstance(c, P) # 間接
True
>>> isinstance(c, Mapping) # 仮想
True
# 実際の継承関係
>>> type(c).__mro__
(<class 'C'>, <class 'P'>, <class 'object'>)
# 「実際の継承」を調べる
>>> Mapping in type(c).__mro__
False
なお、ほとんどのプログラムでは、ユーザー定義のクラスに対して isinstance() を頻繁には使いません。
自分でクラスを開発するなら、オブジェクトのクラスを調べて処理を分岐させるよりも、各クラスに特定の振る舞いをカプセル化するメソッドを定義するほうが、オブジェクト指向に適した書き方です。
例えば、次のような関数があるとします。
def search(obj):
if isinstance(obj, Mailbox):
... # メールボックスを検索するコード
elif isinstance(obj, Document):
... # 文書を検索するコード
elif ...
よりよいアプローチは、search() メソッドをすべてのクラスに定義して、それをただ呼び出すことです:
class Mailbox:
def search(self):
... # メールボックスを検索するコード
class Document:
def search(self):
... # 文書を検索するコード
obj.search()
委譲とは何ですか?¶
委譲はオブジェクト指向の技法 (デザインパターンとも呼ばれます) の 1 つです。
オブジェクト x があり、そのメソッドのうち 1 つだけ振る舞いを変えたいとします。
そのメソッドの新しい実装を持ち、ほかのすべてのメソッドの処理を x の対応するメソッドに委ねるクラスを作れます。
Python では委譲を簡単に実装できます。 例えば、次のクラスはファイルのように振る舞いますが、書き込まれるデータをすべて大文字に変換します。
class UpperOut:
def __init__(self, outfile):
self._outfile = outfile
def write(self, s):
self._outfile.write(s.upper())
def __getattr__(self, name):
return getattr(self._outfile, name)
ここで UpperOut クラスは write() メソッドを定義しなおして、引数の文字列を大文字に変換してから基礎となる self._outfile.write() メソッドを呼び出すようにします。その他すべてのメソッドは基礎となる self._outfile オブジェクトに移譲されます。この委譲は __getattr__() メソッドを通してなされます。属性の制御の詳細は 言語リファレンス を参照してください。
より一般的な場合には、委譲が複雑になることがあります。
属性の取得だけでなく設定も扱うには、クラスに __setattr__() メソッドも定義する必要があり、その実装には注意が必要です。
__setattr__() の基本的な実装は、おおよそ次と同じです。
class X:
...
def __setattr__(self, name, value):
self.__dict__[name] = value
...
__setattr__() の多くの実装では、無限再帰を起こさずに self の属性を設定するため、object.__setattr__() を呼び出します。
class X:
def __setattr__(self, name, value):
# ここに独自の処理を書く...
object.__setattr__(self, name, value)
self.__dict__ に直接エントリーを追加して属性を設定することもできます。
基底クラスで定義されたメソッドを、そのクラスを継承した派生クラスから呼び出すにはどうしますか?¶
組み込みの super() 関数を使ってください:
class Derived(Base):
def meth(self):
super().meth() # Base.meth を呼び出す
この例では、 super() は呼ばれたインスタンス (self の値) を自動判断し、 type(self).__mro__ で method resolution order (MRO メソッド解決順) を検索し、MRO で Derived の次にある Base を返します。
基底クラスを変更しやすいようにコードを構成するにはどうしますか?¶
基底クラスを別名に代入し、その別名を使って継承できます。 こうすれば、別名に代入する値だけを変更すれば済みます。 この方法は、例えばリソースが利用できるかどうかに応じて、使う基底クラスを動的に決めたい場合にも便利です。
class Base:
...
BaseAlias = Base
class Derived(BaseAlias):
...
静的なクラスデータや静的なクラスメソッドを作るにはどうしますか?¶
(C++ や Java の意味で) 静的なデータも静的なメソッドも Python でサポートされています。
静的なデータを作るには、単純にクラス属性を定義してください。その属性に新しい値を代入するには、代入するクラス名を明示する必要があります:
class C:
count = 0 # C.__init__ が呼び出された回数
def __init__(self):
C.count = C.count + 1
def getcount(self):
return C.count # または return self.count
c そのものや c.__class__ から C にいたるパス探索経路上のクラスによってオーバーライドされない限り、c.count も isinstance(c, C) であるすべての c に対する C.count を参照します。
注意: C のメソッド内では、self.count = 42 のような代入は self 自身の辞書に "count" という名前の新しくて関係ないインスタンスを作ります。クラスの静的なデータの再束縛には、メソッド内であるか否かにかかわらず、いつもクラスを指定しなければなりません:
C.count = 314
静的メソッドが使えます:
class C:
@staticmethod
def static(arg1, arg2, arg3):
# 'self' 仮引数はない!
...
しかし、静的メソッドの効果を得るもっと簡単な方法は、単にモジュールレベル関数を使うことです:
def getcount():
return C.count
モジュールごとに 1 つのクラス、または密接に関連するクラス階層を定義する構成なら、この方法で必要なカプセル化を実現できます。
Python でコンストラクタ(やメソッド)をオーバーロードするにはどうしたらいいですか?¶
この回答は実際にはすべてのメソッドに当てはまりますが、通常、この疑問が最初に生じるのはコンストラクタについてです。
C++ では次のように書くでしょう。
class C {
C() { cout << "No arguments\n"; }
C(int i) { cout << "Argument is " << i << "\n"; }
}
Python では、一つのコンストラクタでデフォルトの引数を使ってすべての場合に対応するように書かなければなりません。例えば:
class C:
def __init__(self, i=None):
if i is None:
print("No arguments")
else:
print("Argument is", i)
これで完全に等価とは言えませんが、実用上は十分に近いです。
可変長の引数リストを使う方法もあります。
def __init__(self, *args):
...
これと同じやり方がすべてのメソッド定義で使えます。
__spam を使おうとすると、_SomeClassName__spam に関するエラーが出ます。¶
先頭にアンダースコアが二つ付いた変数名は、クラスのプライベートな変数を、 "マングル化" という単純かつ効率のいい方法で定義します。__spam のような形式 (先頭に二つ以上、末尾にもしあっても一つのアンダースコアがある) のすべての識別子は、classname が先頭のアンダースコアをすべて削除した現在のクラス名とすれば、_classname__spam のように文字上で置換えられます。
クラス内では識別子をそのまま使えますが、クラス外からアクセスするにはマングル化された名前を使う必要があります。
class A:
def __one(self):
return 1
def two(self):
return 2 * self.__one()
class B(A):
def three(self):
return 3 * self._A__one()
four = 4 * A()._A__one()
特に、この仕組みはプライバシーを保証するものではありません。 外部の利用者が意図的にプライベート属性にアクセスすることは可能です。 Python プログラマの多くは、プライベートな変数名をあえて使うことはしません。
参考
詳細と特例は、 private name mangling specifications 。
クラスに __del__ メソッドを定義しているのですが、オブジェクトを削除したときに呼ばれません。¶
いくつかの可能性があります。
del 文は必ずしも __del__() を呼び出すとは限りません -- これは単純にオブジェクトの参照カウントを減らすもので、カウントがゼロになったときに __del__() が呼び出されます。
データ構造に循環参照があると、参照カウントはゼロに戻りません。
例えば、各子が親への参照を持ち、各親が子のリストを持つツリーがこれに当たります。
Python はこうした循環を検出するアルゴリズムを時折実行しますが、データ構造への最後の参照がなくなってからガベージコレクタが動くまでには、時間がかかる場合があります。
そのため、__del__() メソッドが都合の悪い、予測できないタイミングで呼ばれることがあります。
これは問題を再現しようとするときに不便です。
さらに、オブジェクトの __del__() メソッドの実行順序は任意です。
gc.collect() を実行して回収を強制できますが、オブジェクトが決して回収されない特殊な場合も あります。
循環参照を回収する仕組みがあっても、オブジェクトには明示的な close() メソッドを定義し、使い終わったときに呼び出すようにするとよいでしょう。
close() メソッドでは、下位のオブジェクトを参照する属性を削除できます。
__del__() を直接呼び出さないでください。
__del__() から close() を呼び出し、close() は同じオブジェクトに対して複数回呼び出せるように実装してください。
循環参照を避ける他の方法は、 weakref モジュールを使って、参照カウントを増やすことなくオブジェクトを示すことです。例えばツリー構造は、親と (必要なら!) 兄弟に弱参照を使うべきです。
最後に、 __del__() メソッドが例外を発生させた場合、警告のメッセージが sys.stderr に書きこまれます。
与えられたクラスのすべてのインスタンスのリストを得るにはどうしますか?¶
Python はクラス (やビルトイン型) のすべてのインスタンスをたどりません。クラスのコンストラクタにそれぞれのインスタンスへの弱参照のリストを作らせることですべてのインスタンスをたどらせられます。
なぜ id() の結果は一意でないように見えるのですか?¶
組み込みの id() は、オブジェクトが生存している間は一意なことが保証されている整数値を返します。 CPython では、それはオブジェクトのメモリアドレスなので、オブジェクトがメモリから削除された後に、次に新しく生成されたオブジェクトはメモリの同じ場所にメモリ領域を確保されていることが、しばしば起きます。この現象を次の例で示しましょう:
>>> id(1000)
13901272
>>> id(2000)
13901272
この 2 つの id は、それぞれ id() の呼び出し前に作られ、呼び出しの実行直後に削除された、異なる整数オブジェクトのものです。
id を調べるオブジェクトがまだ生存していることを保証するには、そのオブジェクトへの別の参照を作ってください。
>>> a = 1000; b = 2000
>>> id(a)
13901272
>>> id(b)
13891296
いつ is 演算子での同一性テストが頼れますか?¶
is 演算子はオブジェクトの同一性をテストします。 テスト a is b は id(a) == id(b) と同等です。
同一性テストの最も重要な特性は、オブジェクトは常にそれ自身と同一であり、 a is a は常に True を返すということです。 同一性テストは通常、等価性テストよりも高速です。 また、等価性テストとは異なり、同一性テストは真偽値 True または False を返すことが保証されています。
ただし、同一性テストを等価性テストの代用とできるのは、オブジェクトの同一性が保証されている場合 のみ です。 一般的に、同一性が保証される状況は3つあります:
代入は新しい名前を作りますが、オブジェクトの同一性は変えません。
new = oldと代入した後は、new is oldが保証されます。オブジェクトへの参照を格納するコンテナにオブジェクトを入れても、その同一性は変わりません。 リストへの代入
s[0] = xの後は、s[0] is xが保証されます。シングルトンのオブジェクトは、インスタンスが 1 つしか存在できません。
Noneはシングルトンなので、a = Noneとb = Noneを代入した後は、a is bが保証されます。
多くの他の状況では、同一性テストは賢明でなく、等価性テストをお勧めします。 特に、シングルトンであることが保証されていない int や str などの定数をチェックするために同一性テストを使わないでください。
>>> a = 10_000_000
>>> b = 5_000_000
>>> c = b + 5_000_000
>>> a is c
False
>>> a = 'Python'
>>> b = 'Py'
>>> c = b + 'thon'
>>> a is c
False
同様に、ミュータブルなコンテナの新しいインスタンスは同一ではありません:
>>> a = []
>>> b = []
>>> a is b
False
標準ライブラリのコードには、同一性テストを正しく使うための一般的なパターンがあります:
PEP 8 が推奨するとおり、
Noneかどうかを調べるには同一性テストを使うのが望ましい方法です。 コードを自然な英語として読めるうえ、真偽値が偽と評価されるほかのオブジェクトとの混同も避けられます。オプション引数の検出は、
Noneが有効な入力値である場合に厄介なことになる場合があります。この状況では、他のオブジェクトと必ず区別できる唯一のマーカーオブジェクト( singleton sentinel object )を作ることで対策できます。例えば、dict.pop()のように振る舞うメソッドを実装する方法を示します:_sentinel = sentinel('_sentinel') def pop(self, key, default=_sentinel): if key in self: value = self[key] del self[key] return value if default is _sentinel: raise KeyError(key) return default
コンテナの実装では、等価性テストを同一性テストで補強する必要がある場合があります。これは、
float('NaN')のような自分自身と等しくないオブジェクトによってコードが混乱するのを防ぎます。
例えば、collections.abc.Sequence.__contains__() の実装は次のとおりです。
def __contains__(self, value):
for v in self:
if v is value or v == value:
return True
return False
どうすればサブクラスはイミュータブルなインスタンスに格納されたデータを制御できますか?¶
イミュータブルな型のサブクラスを作る場合は、__init__() ではなく __new__() メソッドをオーバーライドしてください。
__init__() が実行されるのはインスタンスが作られた 後 なので、イミュータブルなインスタンスのデータを変更するには遅すぎます。
これらのイミュータブルクラスはすべて、親クラスと異なるシグネチャを持ちます:
import datetime as dt
class FirstOfMonthDate(dt.date):
"常にその月の初日を選ぶ"
def __new__(cls, year, month, day):
return super().__new__(cls, year, month, 1)
class NamedInt(int):
"一部の数値を文字列の名前で指定できるようにする"
xlat = {'zero': 0, 'one': 1, 'ten': 10}
def __new__(cls, value):
value = cls.xlat.get(value, value)
return super().__new__(cls, value)
class TitleStr(str):
"文字列を URL パスに適した名前に変換する"
def __new__(cls, s):
s = s.lower().replace(' ', '-')
s = ''.join([c for c in s if c.isalnum() or c == '-'])
return super().__new__(cls, s)
クラスはこのように使えます:
>>> FirstOfMonthDate(2012, 2, 14)
FirstOfMonthDate(2012, 2, 1)
>>> NamedInt('ten')
10
>>> NamedInt(20)
20
>>> TitleStr('Blog: Why Python Rocks')
'blog-why-python-rocks'
メソッド呼び出しをキャッシュするには どうしたらいいですか?¶
メソッドのキャッシュに使う主なツールは @functools.cached_property と @functools.lru_cache です。
前者はインスタンス単位で、後者はクラス単位で結果を保存します。
cached_property は、引数を受け取らないメソッドにだけ使えます。
インスタンスへの参照は作りません。
キャッシュされたメソッドの結果は、インスタンスが生存している間だけ保持されます。
利点は、インスタンスが使われなくなった場合、キャッシュされたメソッドの結果がすぐに解放されることです。欠点は、インスタンスが溜まると、溜められたメソッドの結果も増えてしまうことです。それらは際限なく増える恐れがあります。
lru_cache は、引数が hashable なメソッドに使えます。
弱参照を渡すように特別な工夫をしない限り、インスタンスへの参照を作ります。
LRU (最も長く使われていないものから削除する) アルゴリズムの利点は、指定された maxsize でキャッシュの大きさを制限できることです。 欠点は、長く使われずにキャッシュから追い出されるか、キャッシュが消去されるまで、インスタンスが生存し続けることです。
この例は各種テクニックを示します:
class Weather:
"政府のウェブサイトで気象情報を調べる"
def __init__(self, station_id):
self._station_id = station_id
# _station_id はプライベートで変更されない
def current_temperature(self):
"1 時間ごとの観測の最新値"
# 古い結果は現在の状況を反映しないことがあるので、
# キャッシュしない。
@cached_property
def location(self):
"観測所の経度・緯度を返す"
# 結果は station_id だけに依存する
@lru_cache(maxsize=20)
def historic_rainfall(self, date, units='mm'):
"指定した日の降水量"
# station_id、date、units に依存する。
上の例は station_id が変わらないことを前提としています。
関係するインスタンス属性が変更される場合、cached_property は属性の変更を検出できないため、この方法は使えません。
To make the lru_cache approach work when the station_id is mutable,
the class needs to define the __eq__() and __hash__()
methods so that the cache can detect relevant attribute updates:
class Weather:
"Example with a mutable station identifier"
def __init__(self, station_id):
self.station_id = station_id
def change_station(self, station_id):
self.station_id = station_id
def __eq__(self, other):
return self.station_id == other.station_id
def __hash__(self):
return hash(self.station_id)
@lru_cache(maxsize=20)
def historic_rainfall(self, date, units='cm'):
'Rainfall on a given date'
# Depends on the station_id, date, and units.
モジュール¶
.pyc ファイルを作るにはどうしますか?¶
モジュールが初めてインポートされたとき (もしくは、現在のコンパイルされたファイルが作られてから、ソースファイルが変更されたとき) 、コンパイルされたコードが入っている .pyc ファイルが、 .py ファイルのあるディレクトリのサブディレクトリ __pycache__ に作成されます。 .pyc ファイルのファイル名は、 .py ファイルの名前で始まり、 .pyc で終わり、中間部分はこのファイルを作った python バイナリに依存した文字列になります。 (詳細は PEP 3147 を参照してください。)
.pyc が作られない理由の 1 つは、ソースファイルがあるディレクトリの権限の問題、つまり __pycache__ サブディレクトリが作れない問題です。これは、例えば、ウェブサーバーでテストを行っているときのような、開発者のユーザと実行者のユーザが別な場合に、起こり得ます。
PYTHONDONTWRITEBYTECODE 環境変数が設定されておらず、Python が __pycache__ サブディレクトリを作成してコンパイル済みモジュールを書き込めるだけの権限や空き容量などを持っていれば、モジュールをインポートすると .pyc ファイルは自動的に作られます。
Python で最上位のスクリプトを実行することはインポートとはみなされず、.pyc は作られません。
例えば、最上位のモジュール foo.py が別のモジュール xyz.py をインポートするとします。
シェルで python foo.py と入力して foo を実行すると、xyz はインポートされるため .pyc が作られますが、foo.py はインポートされないため foo の .pyc は作られません。
foo の .pyc ファイルを作成する -- つまり、インポートされていないモジュールの .pyc ファイルを作成する -- 必要がある場合、 py_compile モジュールと compileall モジュールを使えば可能です。
py_compile モジュールは手動で任意のモジュールをコンパイルできます。やり方の一つは、このモジュールの compile() 関数をインタラクティブに実行することです:
>>> import py_compile
>>> py_compile.compile('foo.py')
これにより、foo.py と同じ場所にある __pycache__ サブディレクトリに .pyc が書き込まれます。
保存先は省略可能な引数 cfile で変更できます。
compileall モジュールを使えば自動的に一つや複数のディレクトリのすべてのファイルをコンパイルできます。シェルプロンプトから compileall.py を起動して、コンパイルしたいファイルを含むディレクトリのパスを指定してください:
python -m compileall .
現在のモジュール名を知るにはどうしますか?¶
モジュールは、あらかじめ定義されたグローバル変数 __name__ を調べることで自分の名前を知ることができます。
値が '__main__' なら、そのプログラムはスクリプトとして実行されています。
通常はインポートして使うモジュールの多くは、コマンドラインインターフェースや自己テストも提供しています。
そのコードは __name__ を確認した場合にだけ実行します。
def main():
print('Running test...')
...
if __name__ == '__main__':
main()
相互にインポートしあうモジュールを作るにはどうしたらいいですか?¶
以下のモジュールがあったとしましょう:
foo.py:
from bar import bar_var
foo_var = 1
bar.py:
from foo import foo_var
bar_var = 2
問題はインタプリタが以下の段階を実行することです:
main が
fooをインポートするfooの空のグローバルが生成されるfooがコンパイルされ実行を始めるfooがbarをインポートするbarの空のグローバルが生成されるbarがコンパイルされ実行を始めるbarがfooをインポートする(すでにfooという名前のモジュールがあるので no-op となる)インポートメカニズムは
fooのグローバルからfoo_varを読んで、bar.foo_var = foo.foo_varに設定しようとします。
この最後の段階は失敗します。Python が foo を解釈し終わっていなくて、foo のグローバルなシンボルの辞書はまだ空ですから。
import foo を使って、グローバルコードの foo.foo_var にアクセスしようとしたときにも、これと同じことが起こります。
この問題には (少なくとも) 三つの解決策があります。
Guido van Rossum は from <module> import ... を一切使わず、すべてのコードを関数内に置くことを勧めています。
グローバル変数やクラス変数の初期化には、定数か組み込み関数だけを使います。
つまり、インポートしたモジュール内のものはすべて <module>.<name> として参照します。
Jim Roskind はそれぞれのモジュールに対して以下の順に進めることを提案しています:
エクスポート (インポートされた基底クラスを必要としないグローバル、関数、クラス)
import文アクティブなコード (インポートされた値によって初期化されるグローバルを含む)。
インポートが奇妙な場所に現れることから Van Rossum はこの方法をそれほど好みませんが、これは有効です。
Matthias Urlichs は第一に再帰インポートが必要ないようにコードを構築しなおすことを推奨しています。
これらの解決策はそれぞれ両立させることもできます。
__import__('x.y.z') は <module 'x'> を返しますが、z を得るためにはどうしますか?¶
importlib に import_module() という便利な関数があるので、代わりにそちらを使用することを検討してください。
z = importlib.import_module('x.y.z')
インポートされたモジュールを編集してから再インポートしましたが、変化が現れません。なぜですか?¶
効率と一貫性上の理由から、Python はモジュールが最初にインポートされた時にのみモジュールファイルを読み込みます。そうしないと、たくさんのモジュールでできていて、それぞれが同じ基本モジュールをインポートしているようなプログラムでは、その基本モジュールの解析と再解析が繰り返されることになります。変更されさたモジュールの再読込を強制するには、こうしてください:
import importlib
import modname
importlib.reload(modname)
注意: この方法は万全ではありません。 特に、
from modname import some_objects
のような文を含むモジュールは、インポートされたオブジェクトの古いバージョンを使い続けます。そのモジュールにクラス定義が含まれていたら、存在するクラスインスタンスは新しいクラス定義を使うようにアップデート されません。これによって以下の矛盾した振舞いがなされえます:
>>> import importlib
>>> import cls
>>> c = cls.C() # C のインスタンスを作る
>>> importlib.reload(cls)
<module 'cls' from 'cls.py'>
>>> isinstance(c, cls.C) # isinstance が偽になる!
False
クラスオブジェクトの「識別値」を表示すると、この問題の原因がはっきりします。
>>> hex(id(c.__class__))
'0x7352a0'
>>> hex(id(cls.C))
'0x4198d0'