Lesson 8
特別な属性
目次
Lesson 8
Chapter 1
はじめに
Lesson 8
Chapter 2
__name__と__main__
__name__変数はプログラム実行時に自動で生成され、実行中のスクリプトのモジュール名が格納されます。
例えば、test.pyがメインのスクリプトとして実行されるとき、__name__は"__main__"
になります。
また、test.pyというモジュールが他のスクリプトにインポートされている場合、test.pyの__name__は
"test"
になります。
これにより、プログラムが直接実行されているか、他のスクリプトからインポートされているかを判断することができます。
実際にPythonファイルを用意して実行してみましょう。また、このレッスンでは「Visual Studio Code」というエディターを用いてテストをしていきますが、ご自身が普段使用しているエディターでも構いません。 フォルダツリーと各ファイル内容は以下の通りです。
TEST_PROJECT
├ test_01.py
└ test_02.py
test_01.py
from test_02 import sample_func
print(__name__)
sample_func()
test_02.py
def sample_func():
print(__name__)
このプログラムは、test_01.py
とtest_02.py
の__name__
をそれぞれ出力するプログラムとなっています。
これらのファイルを用意できたらtest_01.py
を実行します。実行方法については各環境によって少し異なる場合がありますが、基本的にはIDEのコンソール画面からpython
コマンドでtest_01.py
を実行する方法と、IDE上に用意されているプログラム実行ボタンを押して実行します。
$ python test_01.py
出力結果
__main__
test_02
するとこのような出力結果となります。どちらもprint(__name__)
という同じ処理ですが、モジュールとしてインポートされたtest_02.py
の方では自身のモジュール名(ファイル名)が__name__
に格納されていることが確認できます。
一方で、スクリプトとして実行したtest_01.py
には__main__
という文字が格納されています。これが__name__
の仕組みです。
__main__の主な使用用途
また、これらの変数を使用することで、インポートされたスクリプトなのか、スクリプトとして実行されているのかを判断することができます。これは、スクリプト内で特定のセットアップや処理を行う必要がある場合に利用されます。 例えば、スクリプトがインポートされる場合は特定のセットアップを行わないようにするために、次のように書くことができます。
sample.py
if __name__ == "__main__":
# この中にスクリプトとして実行される場合にのみ実行される処理を記述する
__name__
変数は、そのスクリプトがメインとして実行されるときに__main__
となるため、上記の条件式はTrueになります。
以上が、__name__
変数と__main__
の概要となります。

Lesson 8
Chapter 3
__path__
__path__
変数は、Pythonのパッケージを探索するために使用される検索パスのリストを表す特殊変数です。これは、Pythonがインポートするパッケージの場所(パス)を参照するために使用されます。
例えば、test_package
というパッケージが/home/user/scripts
にある場合__path__
は「/home/user/scripts」になります。この変数は、パッケージがインポートされるときに自動的に設定されます。
このチャプターでも実際の使用方法を確認してみましょう。先程のtest_project
を流用して以下の構成とします。また、__init__.py
の中身には何も記述をしません。
TEST_PROJECT
├ test_package
│ └ __init__.py
├ test_01.py
└ test_02.py
test_01.py
import test_02
import test_package
print(test_package.__path__)
出力結果
['/Users/developer/test_project/test_package']
上記の出力結果は実行環境によって異なる場合がありますので、ご自身の環境でご確認ください。
ここではtest_package
というフォルダ(パッケージ)を用意して、test_01.py
でそれをインポートし、パッケージの__path__
を出力するといった処理の流れになっています。
では、内容を少し変更してtest_02
モジュールのパスを出力してみます。
test_01.py
import test_02
import test_package
print(test_02.__path__)
出力結果
traceback (most recent call last):
File "/Users/developer/test_project/test_01.py", line 4, in <module>
print(test_02.__path__)
AttributeError: module 'test_02' has no attribute '__path__'. Did you mean: '__name__'?
どうやら上手く出力出来なかった様です。これはtest_02
がパッケージではなくモジュールであることが原因となります。
パッケージとモジュールの違い
パッケージやモジュールと行った概念が出てきたと思いますが、具体的な違いについて学んでいきましょう。
パッケージは複数のモジュールをまとめており、モジュールは〇〇.py
ファイル単体を指すことが多いです。
また、Pythonのパッケージはフォルダ(ディレクトリ)として存在することが一般的ですが、主な見分け方としては、そのファイル内に__init__.py
ファイルがあるということです。
Pythonではこの__init__.py
ファイルがある場合に、そのフォルダをパッケージとして認識します。
以上が、__path__
の概要となります。

Lesson 8
Chapter 4
__dict__
__dict__
変数は、オブジェクトが持つ変数やメソッドを格納した辞書型オブジェクトです。主にオブジェクトの中に格納されている変数やメソッドにアクセスするために使用されます。
オブジェクト指向プログラミングにおいて、オブジェクトは、変数(属性やプロパティ)とメソッドを持ちます。__dict__
は、変数やメソッドの名前をキー、その値を値として格納されています。
また__dict__
変数を使用することで、オブジェクトの中に格納されている変数や関数にアクセスしたり、変数や関数を追加・削除したりすることができます。
プロパティの参照
では、実際に__dict__
を使用してオブジェクトの内容を確認してみましょう。
sample.py
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
def my_method(self):
print("Hello, World!")
obj = MyClass()
print(obj.__dict__)
出力結果
{'x': 1, 'y': 2}
上記の例ではMyClass
クラスのインスタンスであるobj
の内容に関して出力しています。
コンストラクタによって定義されているインスタンス変数のx
とy
がプロパティとして辞書型で格納されていることが確認できます。
また__dict__
変数を使用して、既に存在する特定のプロパティを参照する場合は以下のようにします。
sample.py
〜省略〜
print(obj.__dict__["x"])
出力結果
1
特定のプロパティを参照する場合も、通常の辞書型と変わりありません。また、本来のオブジェクトに対してのプロパティ参照方法であるprint(obj.x)
の記述と結果は変わりません。
注意点として、メソッドの内容は格納されません。また、プロパティが存在しないオブジェクトに対して__dict__
変数を使用して参照しようとしてもエラーとなります。
プロパティの追加と変更
__dict__
変数を使用したプロパティの追加方法については以下の通りです。
sample.py
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
obj = MyClass()
obj.__dict__["z"] = 3
print(obj.__dict__)
出力結果
{'x': 1, 'y': 2, 'z': 3}
このようにコンストラクタでは定義されていないz
という変数を追加出来ている事が確認できます。また、こちらも
obj.z = 3
という記述でも結果は同じになります。
次に、既に存在するプロパティの変更については以下のとおりです。
sample.py
〜省略〜
obj = MyClass()
obj.__dict__["x"]= 3
print(obj.__dict__)
出力結果
{'x': 3, 'y': 2}
こちらも通常の辞書型と同じくインデックスにキーを指定し、そのバリューに対して値を代入(上書き)しています。
また、obj.x= 3
という記述でも結果は同じになります。
プロパティの削除
__delattr__
というクラスメソッドを使用することで、特定のプロパティを削除することが出来ます。
sample.py
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
obj = MyClass()
obj.__delattr__("x")
print(obj.__dict__)
出力結果
{'y': 2}
このように__delattr__()
の引数に、削除対象のプロパティのキーを渡すことで削除することが出来ます。
以上が、__dict__
を使用したオブジェクト情報の参照・操作となります。これらを使いこなすことで、複数のプロパティが存在するオブジェクトの情報を簡単に参照することができ、その内容を必要に応じて変更することが容易になります。

Lesson 8
Chapter 5
__annotations__
__annotations__
はPython3.0から導入された機能で、関数の引数や返り値の型(アノテーション)に関する情報を参照し型チェックをする事ができます。
また、Pythonにおけるアノテーションとは"型ヒント"と呼ばれる機能を使用して定義します。こちらについては後ほど詳しく説明していきます。
アノテーションの宣言
アノテーションは関数やメソッドに記述します。以下は、引数a
が整数型で,
b
が文字型であることを示す例です。
sample.py
def add(a: int, b: str):
return a + int(b)
このようにアノテーションを使うことで、関数やメソッドがどのような型の引数を受け取り、返り値を返すのかが明確になります。
また、関数やメソッドの返り値にもアノテーションを宣言することが出来ます。
sample.py
def add(a: int, b: str) -> int:
return a + int(b)
返り値の場合 -> [データ型]
といった形で宣言します。
上記の例では返り値が整数型であることを示すint
が宣言されています。
また、より詳細に関数の説明を記述するドキュメンテーションとしても使用することができます。以下は、関数の説明をアノテーションで記述する例です。
sample.py
def add(a: int, b: int) -> int:
"""
2つの整数を足し合わせる関数です。
:param a: 足し算の左辺の整数
:param b: 足し算の右辺の整数
:return: 足し算の結果
"""
return a + b
アノテーションは実行時には影響を及ぼしません。しかし、アノテーションを使うことで、開発者がより正確に関数やメソッドを記述することができ、バグを減らすことができます。
Pythonにおける型ヒント
ここまで学習してきたアノテーションの宣言には、Pythonの型ヒントという構文が用いられています。ここでは型ヒントについてもう少し学んでいきましょう。
変数に対しての型ヒントの書き方は以下の通りです。
[変数]: [データ型]
このように:(コロン)
で変数とデータ型を記述することで使用することが出来ます。
また、データ型に使用できる代表的な型は以下の通りです。
データ型 | 説明 |
---|---|
int | 整数 |
float | 浮動小数点数 |
bool | 真偽値 |
str | 文字列 |
list | リスト |
tuple | タプル |
dict | 辞書 |
set | 集合 |
None | None型 |
それでは実際に__annotations__
を使用して、これらのアノテーションを確認する方法について学んでいきましょう。
アノテーションの参照方法
__annotations__
は関数(メソッド)に対して使用することが出来ます。以下の例ではsay_hello
メソッドのアノテーションを参照しています。
sample.py
def my_hello(name: str, age: int) -> str:
message = "私は" + name + "です。年齢は" + str(age) + "歳です。"
return message
print(my_hello("太郎", 20))
print(my_hello.__annotations__)
出力結果
私は太郎です。年齢は20歳です。
{'name': <class 'str'>, 'age': <class 'int'>, 'return': <class 'str'>}
このように、アノテーション情報が辞書型で各属性に格納されていることが確認できます。
以上が__annotations__
変数についての説明になります。アノテーションは、関数やメソッドがどのような型の引数を受け取り、どのような型の返り値を返すのかを明確にするための仕組みであり、ドキュメントとしても使用することができます。
