アンダースコアなのかアンダーバーなのか
そんなことはどっちでも良い。
問題はpythonでアンダースコア(アンダーバー)がよく登場することだ。
お品書き。
- 1つのアンダースコアから始まる属性名(
_var
) - 2つのアンダースコアから始まる属性名(
__var
) - 1つのアンダースコアで終わる属性名(
var_
) - 2つのアンダースコアから始まり、2つのアンダースコアで終わる属性名(
__var__
) - アンダースコアだけ(
_
)
属性っていうと、メソッドと変数の両方をさせるらしい。
1つのアンダースコアから始まる属性名(_var
)
PEP8
_single_leading_underscore
: weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an underscore. (https://www.python.org/dev/peps/pep-0008/)
1つのアンダースコアから始まる属性名は内部での使用を目的としている属性であることを示唆する。
変数の場合
以下のように初期化したクラスを外部から読み込んで変数名の付け方による挙動の違いを見てみる。
class Test: def __init__(self): self.foo = 11 self._bar = 23
>>> t = Test() >>> t.foo 11 >>> t._bar 23
上記のように、どちらの場合も外部からアクセスできてしまう。だめやん。
モジュールの場合
一方、モジュール名として、1つのアンダースコアから始まるモジュールを定義すると、
def ext_func(): return 23 def _int_func(): return 42
外部からワイルドカード指定でimport
した際には読み込まれない。
いいね。
>>> from my_module import * >>> ext_func() 23 >>> _int_func() Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name '_int_func' is not defined
しかし、ワイルドカードで指定しない場合、この変数名は通常通り呼び出すことができる。え、だめやん。
>>> import my_module >>> my_module.ext_func() 23 >>> my_module.int_func() 42
まとめ
PEP8ではモジュールの読み込みにワイルドカードを使用することは推奨されていない。
モジュールを読み込む時は明示的に指定することが想定される。
けどそれだと普通に外部から読み込まれてしまう。。
1つのアンダースコアから始まる属性名は、プライベート変数だよ!!
だけど動作にはほとんど影響しないので、そこんとこ理解しといて!!
ってことらしい。
2つのアンダースコアから始まる属性名(__var
)
PEP8
double_leading_underscore: when naming a class attribute, invokes name mangling (inside class FooBar, boo becomes _FooBar__boo; see below). (https://www.python.org/dev/peps/pep-0008/)
この属性名で定義すると、名前のマングリング機構を呼び出すことで、擬似的にプライベート属性を作成する。
具体的には以下のようなマングリングを引き起こす。
__attr
→ _Class__attr
To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.
Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.
このマングリングは、プライベート変数にするためというより、
親クラスと子クラスでメソッド名が重複した場合に、コンフリクトを避ける目的で使うのが一般的らしい。
2つのアンダースコアから始まり、2つのアンダースコアで終わる属性名(__var__
)
PEP8
__double_leading_and_trailing_underscore__
: "magic" objects or attributes that live in user-controlled namespaces. E.g.__init__
,__import__
or__file__
. Never invent such names; only use them as documented. (https://www.python.org/dev/peps/pep-0008/)
公式ドキュメント
クラスは、特殊な名前のメソッドを定義して、特殊な構文 (算術演算や添え字表記、スライス表記など) による特定の演算を実装できます。これは、Python の演算子オーバロード (operator overloading) へのアプローチです。これにより、クラスは言語の演算子に対する独自の振る舞いを定義できます。例えば、あるクラスが
__getitem__()
という名前のメソッドを定義しており、 x がこのクラスのインスタンスであるとすると、 x[i] はtype(x).__getitem__(x, i)
とほぼ等価です。(https://docs.python.jp/3.3/reference/datamodel.html)
俗にいう特殊属性(magic variable)。 何も "magic" ではなく、この呼び方はPythonコミュニティで嫌われている(らしい)。 定められた特殊メソッド名がクラス内で定義されている場合、特定の演算が行われた値が返るようになっている。 自作関数の属性名をこの形式で作るのはやめるべし。
1つのアンダースコアで終わる属性名(var_
)
PEP8
single_trailing_underscore_
: used by convention to avoid conflicts with Python keyword (https://www.python.org/dev/peps/pep-0008/)
属性名のpython予約語とのコンフリクトを避けるために使用される。
予約語は以下の通り。
False class finally is return None continue for lambda try True def from nonlocal while and del global not with as elif if or yield assert else import pass break except in raise
以下のように使用される。
Tkinter.Toplevel(master, class_="ClassName")
アンダースコアだけ(_
)
アンダーバー1文字の使い方。
for i in range(10): print('Hello World!')
forループの中で格納した値を使用していない場合。こういう時は_
を使う。
for _ in range(10): print('Hello World!')
またはタプル中の要素のうち、特定の要素だけ使用したい場合。
>>> test = ('a', 'b', 'iranai_1', 'iranai_2') >>> a, b, _, _ = test >>> a 'a' >>> b 'b'
その他、対話型ウィンドウ (REPL)で起動している際は、直前に実行したコマンドの標準出力が格納されている。
ちょっとしたテストに便利。
>>> 3 + 5 8 >>> _ 8 >>> print(_) 8 >>> list() [] >>> _.append(1) >>> _.append(2) >>> _.append(3) >>> _ [1, 2, 3]
dunders
とはなんなのか。
pythonのコードではこの2つ続きのアンダースコアがよく使われるため、
腕利きのpythonista達は、2つ続きのアンダースコア(__
)をdundersと呼ぶらしい。
double underscore
→ dunders
そいういうことだ。
参考

Python Tricks: A Buffet of Awesome Python Features (English Edition)
- 作者:Bader, Dan
- 発売日: 2017/12/06
- メディア: Kindle版