プログラミング FAQ¶
目次
一般的な質問¶
ブレークポイントやシングルステップ実行などを備えたソースコードレベルデバッガはありますか?¶
はい。
Python 用のデバッガについては次に解説してあり、組み込みの breakpoint()
関数でそれらのデバッガに処理を移せます。
pdb モジュールは簡素にして十分な Python のコンソールモードデバッガです。これは Python の標準ライブラリに含まれているもので、 ライブラリリファレンスマニュアルにドキュメントがあります
。 pdb のコードを手本にして自分用のデバッガを書くこともできます。
Python に同梱されている統合開発環境の IDLE は通常の Python の配布形態の一部 (普通は Tools/scripts/idle3 から利用可能) であり、グラフィカルなデバッガを含んでいます。
PythonWin は、pdb をベースとした GUI デバッガを含む Python IDE です。Pythonwin デバッガは、ブレークポイントの色付けや非 PythonWin プログラムのデバッグなどの素敵な機能をたくさん持っています。PythonWin は pywin32 プロジェクトの一部、あるいは ActivePython ディストリビューションの一部として利用可能です。
Eric は PyQt や Scintilla editing component をもとにした IDE です。
trepan3k は gdbライクなデバッガです。
Visual Studio Code はバージョン管理ソフトと一緒になったデバッグツールを備えた IDE です
商業のグラフィカルデバッガ付き Python IDE もあります。例えば:
バグの発見や静的解析に役立つツールはありますか?¶
はい。
Pylint と Pyflakes は、バグの早期発見に役立つ基本的なチェックを行います。
Mypy, Pyre, 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: local variable 'x' referenced before assignment
これは、あるスコープの中で変数に代入を行うとき、その変数はそのスコープに対してローカルになり、外のスコープにある同じ名前の変数を隠すからです。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
、PIL.Image
、など自前で開発したモジュール
循環参照の問題を避けるために、インポートを関数やクラスに移すことが必要なときもあります。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 # ints are immutable
>>> y = x
>>> x = x + 1 # 5 can't be mutated, we are creating a new object here
>>> 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 and b are local names ... b = b + 1 # assigned to new objects ... return a, b # return new values ... >>> x, y = 'old-value', 99 >>> func1(x, y) ('new-value', 100)
これはたいてい一番明確な方法です。
グローバル変数を使って。これはスレッドセーフでないので、推奨されません。
ミュータブルな (インプレースに変更可能な) オブジェクトを渡すことによって:
>>> def func2(a): ... a[0] = 'new-value' # 'a' references a mutable list ... a[1] = a[1] + 1 # changes a shared object ... >>> args = ['old-value', 99] >>> func2(args) >>> args ['new-value', 100]
変更される辞書に渡すことによって:
>>> def func3(args): ... args['a'] = 'new-value' # args is a mutable dictionary ... args['b'] = args['b'] + 1 # change it in-place ... >>> 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 is a mutable Namespace ... args.b = args.b + 1 # change object in-place ... >>> 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__ inherited
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
か決めることはできないのです。
概して、コードにとってある値の「名前を知っている」事は重要ではありません。あなたがわざと内省的なコードを書いているのでない限り、方針を変えた方がいいかもしれないということになるでしょう。
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
# Primes < 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)))))
# First 10 Fibonacci numbers
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))))
# Mandelbrot set
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))
# \___ ___/ \___ ___/ | | |__ lines on screen
# V V | |______ columns on screen
# | | |__________ maximum of "iterations"
# | |_________________ range on y axis
# |____________________________ range on x axis
よい子はまねしないでね!
関数の引数リストにあるスラッシュ (/) は何を意味しますか?¶
パラメータ関数の仮引数にあるスラッシュは、それより前にある仮引数は位置専用引数であることを示します。
位置専用引数は、外で使える名前を持たない仮引数です。
位置専用引数を受け付ける関数の呼び出しにおいて、実引数はその位置だけに基づいて仮引数に対応付けられます。
例えば、 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 にも C の一貫性があって、i % j
が i
と同じ符号を持つように i // j
を丸めています。
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()
を使ってください。
手の込んだフォーマット形式を使うなら、 フォーマット済み文字列リテラル と 書式指定文字列の文法 の節を参照してください。
例えば、 "{:04d}".format(144)
は '0144'
になり、 "{:.3f}".format(1.0/3.0)
は '0.333'
になります。
文字列をインプレースに変更するにはどうしたらいいですか?¶
文字列はイミュータブルなので、それはできません。殆どの場合、組み立てたい個別の部品から単純に新しい文字列を構成するべきです。しかし、Unicode データをインプレースに変更できるオブジェクトが必要なら、 array
モジュールの io.StringIO
オブジェクトを試してください:
>>> 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('u', s)
>>> print(a)
array('u', 'Hello, world')
>>> a[0] = 'y'
>>> print(a)
array('u', 'yello, world')
>>> a.tounicode()
'yello, world'
関数やメソッドを呼ぶのに文字列を使うにはどうしたらいいですか?¶
様々なテクニックがあります。
一番いいのは、文字列を関数に対応させる辞書を使うことです。このテクニックの一番の利点は、文字列が関数の名前と同じ必要がないことです。この方法は case 構造をエミュレートするための一番のテクニックでもあります:
def a(): pass def b(): pass dispatch = {'go': a, 'stop': b} # Note lack of parens for funcs dispatch[get_input()]() # Note trailing parens to call function
組み込み関数の
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()
関数を使ってください (また、中程度に高度な例は、 ソート HOW TO を参照してください)。抽象化は、遠回りにしがちで、インタプリタの作業を増やすことになります。この遠回りさが、なされる作業の量より重大になると、プログラムが遅くなってしまいます。過度な抽象化、特に細かい関数やメソッドの形で現れるもの (これは読みにくさも落とします) は防ぐべきです。
pure Python にできる限界に達したなら、更に進むためのツールがあります。例えば、Cython は、Python コードのわずかに変形した版を C 拡張にコンパイルし、多種のプラットフォームで使えます。Cython は、コンパイル (と任意の型アノテーション) を利用し、コードの解釈を大幅に速くします。C プログラミングに自信があるなら、自分で write a C extension module こともできます。
参考
パフォーマンス 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):
... # do something with 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 の同じリストへの参照を含むリストを作ります。一つの列に対する変更はすべての列に現れますが、これが望んだ結果であることはまずないでしょう。
おすすめの方法は、最初に望んだ長さのリストを作り、それから新しく作ったリストでそれぞれの要素を埋めていくことです:
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 が最もよく知られています。
オブジェクトのシーケンスにメソッドを適用するにはどうしますか?¶
リスト内包表記を使ってください:
result = [obj.method() for obj in mylist]
なぜ加算はされるのに 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
例外が送出された理由は明らかです: 1
が (1
) を指すオブジェクト a_tuple[0]
に加えられ、結果のオブジェクト 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]))
リストを別のリストの値によってソートするにはどうしますか?¶
二つのイテレータを混ぜあわせてタプルのイテレータにしてから、必要な要素を選んでください。
>>> 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 文の実行で生成される特殊なオブジェクトです。クラスオブジェクトはインスタンスオブジェクトを生成するためのテンプレートとして使われ、あるデータ型に特有のデータ (attribute/属性) とコード (メソッド) の両方を内蔵しています。
新しいクラスを一つ以上の他のクラス (新しいクラスの基底クラスと呼ばれます) に基づいて作ることもできます。この新しいクラスは、基底クラスから属性とメソッドを継承します。これにより、オブジェクトモデルを継承で連続的に洗練できます。メールボックスへの基本的なアクセサを提供する一般的な 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, ...))
のようにすれば、あるオブジェクトが任意の数のクラスのオブジェクトであるかを調べられますし、isinstance(obj, str)
や isinstance(obj, (int, float, complex))
のようにすれば、Python のビルトイン型のオブジェクトであるかも調べられます。
注意: isinstance()
は abstract base class (抽象基底クラス)からの仮想継承もチェックします。そのため、登録 (register) されたクラスが直接/間接的にそれを継承していなくても True
を返します。「真のインスタンス」をテストする場合は、クラスの MRO を調べます:
from collections.abc import Mapping
class P:
pass
class C(P):
pass
Mapping.register(P)
>>> c = C()
>>> isinstance(c, C) # direct
True
>>> isinstance(c, P) # indirect
True
>>> isinstance(c, Mapping) # virtual
True
# Actual inheritance chain
>>> type(c).__mro__
(<class 'C'>, <class 'P'>, <class 'object'>)
# Test for "true inheritance"
>>> Mapping in type(c).__mro__
False
なお、大部分のプログラムでは、 isinstance()
をユーザー定義のクラスに何度も使うべきではありません。クラスを自分で開発するときに、適切なオブジェクト指向スタイルは、特定の振る舞いをカプセル化するクラスのメソッドを定義するものであって、オブジェクトのクラスを調べてそのクラスに応じて違うことをするものではありません。例えば、何かをする関数があったとして:
def search(obj):
if isinstance(obj, Mailbox):
... # code to search a mailbox
elif isinstance(obj, Document):
... # code to search a document
elif ...
よりよいアプローチは、search()
メソッドをすべてのクラスに定義して、それをただ呼び出すことです:
class Mailbox:
def search(self):
... # code to search a mailbox
class Document:
def search(self):
... # code to search a document
obj.search()
委譲とは何ですか?¶
委譲 (delegation) とは、オブジェクト指向のテクニック (デザインパターンとも呼ばれる) の一つです。オブジェクト x
があって、そのメソッドのうちただ一つの振る舞いを変えたいとしましょう。新しいクラスを作成し、変えたいメソッドだけを新しく実装し、他のすべてのメソッドを 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.__dict__
を変更して、無限再帰を起こすことなくローカルな状態を保存するようにしなければなりません。
基底クラスで定義されたメソッドを、そのクラスを継承した派生クラスから呼び出すにはどうしますか?¶
組み込みの super()
関数を使ってください:
class Derived(Base):
def meth(self):
super().meth() # calls Base.meth
この例では、 super()
は呼ばれたインスタンス (self
の値) を自動判断し、 type(self).__mro__
で method resolution order (MRO メソッド解決順) を検索し、そしてMRO内で Derived
の次行を返します: Base
。
基底クラスの名前を変えやすいコードを書くにはどうしますか?¶
基底クラスをエイリアス (alias) に代入しておいてから、そのエイリアスを継承するといいかもしれません。そうすればエイリアスに代入する値を変えるだけで済みます。ちなみに、この手法は使用する基底クラスを動的に選びたいとき、例えば使えるリソースによって選びたいときなどにも便利です。例:
class Base:
...
BaseAlias = Base
class Derived(BaseAlias):
...
静的なクラスデータや静的なクラスメソッドを作るにはどうしますか?¶
(C++ や Java の意味で) 静的なデータも静的なメソッドも Python でサポートされています。
静的なデータを作るには、単純にクラス属性を定義してください。その属性に新しい値を代入するには、代入するクラス名を明示する必要があります:
class C:
count = 0 # number of times C.__init__ called
def __init__(self):
C.count = C.count + 1
def getcount(self):
return C.count # or 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):
# No 'self' parameter!
...
しかし、静的メソッドの効果を得るもっと簡単な方法は、単にモジュールレベル関数を使うことです:
def getcount():
return C.count
モジュールあたりに一つのクラスを定義するように (あるいはクラス組織を厳密に関連させるように) コードが構成されているなら、これで必要なカプセル化ができます。
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
のように文字上で置換えられます。
これはプライベートであることを保証するものではありません。これでも外部のユーザが "_classname__spam" 属性に直接アクセスできますし、プライベートな変数はオブジェクトの __dict__
から見えます。多くの Python プログラマはわざわざプライベートな変数名を使おうとなど考えません。
クラスに __del__ メソッドを定義しているのですが、オブジェクトを削除したときに呼ばれません。¶
いくつかの可能性があります。
del
文は必ずしも __del__()
を呼び出すとは限りません -- これは単純にオブジェクトの参照カウントを減らすもので、カウントがゼロになったときに __del__()
が呼び出されます。
データ構造が循環リンク (子のそれぞれが親の参照を持ち、親のそれぞれが子のリストを持つツリーなど) を含む場合、その参照カウントは決して 0 にはなりません。時々、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つあります:
1) 代入は新しい名前を作りますが、オブジェクトIDは変えません。 new = old
代入の後、 new is old
が保証されます。
2) オブジェクト参照を格納するコンテナにオブジェクトを入れても、オブジェクトIDは変わりません。 s[0] = x
リスト代入の後、 s[0] is x
が保証されます。
3) オブジェクトがシングルトンなら、それはそのオブジェクトのインスタンスは1つだけ存在できることを意味します。 a = None
と b = None
代入の後、 a is b
が保証されます。None
がシングルトンのためです。
多くの他の状況では、同一性テストは賢明でなく、等価性テストをお勧めします。 特に、シングルトンであることが保証されていない int
や str
などの定数をチェックするために同一性テストを使わないでください。
>>> a = 1000
>>> b = 500
>>> c = b + 500
>>> a is c
False
>>> a = 'Python'
>>> b = 'Py'
>>> c = b + 'thon'
>>> a is c
False
同様に、ミュータブルなコンテナの新しいインスタンスは同一ではありません:
>>> a = []
>>> b = []
>>> a is b
False
標準ライブラリのコードには、同一性テストを正しく使うための一般的なパターンがあります:
1) PEP 8 で推奨されるように、同一性テストは None
のチェックの良い方法です。 コードの中で平易な英語のように読めますし、 false と評価される真偽値を持ちうる他のオブジェクトとの混同を避けます。
2) None
が有効な入力値である場合、省略された引数を検出にはコツがいります。 そのような状況では、他のオブジェクトと区別されることが保証されたシングルトンの番兵オブジェクトを作れます。 例えば、これは dict.pop()
のように振る舞うメソッドを実装する方法です:
_sentinel = object()
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
3) コンテナの実装では、等価性テストを同一性テストで補強しないといけない場合があります。 これは、 float('NaN')
のような自分自身と等価でないオブジェクトによってコードが混乱するのを防ぐためです。
For example, here is the implementation of
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__()
メソッドを継承します。 前者はインスタンスが生成された 後 に動くため、イミュータブルなインスタンスのデータを変えるには遅すぎます。
これらのイミュータブルクラスはすべて、親クラスと異なるシグネチャを持ちます:
from datetime import date
class FirstOfMonthDate(date):
"Always choose the first day of the month"
def __new__(cls, year, month, day):
return super().__new__(cls, year, month, 1)
class NamedInt(int):
"Allow text names for some numbers"
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):
"Convert str to name suitable for a URL path"
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'
メソッド呼び出しをキャッシュするには どうしたらいいですか?¶
メソッドキャッシュの主な道具は2つあり、 functools.cached_property()
と functools.lru_cache()
です。前者はインスタンスレベル、後者はクラスレベルで結果を保存します。
cached_property アプローチは、引数を取らないメソッドでのみ働きます。これはインスタンスへの参照を作りません。キャッシュされたメソッドの結果は、インスタンスが生きている間だけ保持されます。
利点は、インスタンスが使われなくなった場合、キャッシュされたメソッドの結果がすぐに解放されることです。欠点は、インスタンスが溜まると、溜められたメソッドの結果も増えてしまうことです。それらは際限なく増える恐れがあります。
The lru_cache approach works with methods that have hashable arguments. It creates a reference to the instance unless special efforts are made to pass in weak references.
least recently used アルゴリズム(訳注:LRU 直近に使われたものを残す)の利点は、キャッシュが指定された maxsize で制限されることです。欠点は、キャッシュから期限切れで追い出されるかクリアされるまで、インスタンスが生き続けることです。
この例は各種テクニックを示します:
class Weather:
"Lookup weather information on a government website"
def __init__(self, station_id):
self._station_id = station_id
# The _station_id is private and immutable
def current_temperature(self):
"Latest hourly observation"
# Do not cache this because old results
# can be out of date.
@cached_property
def location(self):
"Return the longitude/latitude coordinates of the station"
# Result only depends on the station_id
@lru_cache(maxsize=20)
def historic_rainfall(self, date, units='mm'):
"Rainfall on a given date"
# Depends on the station_id, date, and units.
上の例では、 station_id が常に変わらないことを前提としています。関連するインスタンスの属性が可変である場合、 cached_property アプローチは属性の変更を検出できないため、機能しなくなります。
The lru_cache approach can be made to work, but the class needs to define the __eq__ and __hash__ methods so 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
はインポートされるので 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)
注意:この手法は 100%安全とは言えません。とりわけ
from modname import some_objects
のような文を含むモジュールは、インポートされたオブジェクトの古いバージョンを使い続けます。そのモジュールにクラス定義が含まれていたら、存在するクラスインスタンスは新しいクラス定義を使うようにアップデート されません。これによって以下の矛盾した振舞いがなされえます:
>>> import importlib
>>> import cls
>>> c = cls.C() # Create an instance of C
>>> importlib.reload(cls)
<module 'cls' from 'cls.py'>
>>> isinstance(c, cls.C) # isinstance is false?!?
False
この問題の本質は、クラスオブジェクトの "固有値" を印字することで明らかになります:
>>> hex(id(c.__class__))
'0x7352a0'
>>> hex(id(cls.C))
'0x4198d0'