Pythonの変数の実体、気になりませんか?
仕事や、kaggleでPythonを使っていると、csvファイルの処理でPandasを使うことが多いと思います。
Pandasを用いるということは、基本的にDataFrameを操作するということとワンセットですよね。
このDataFrameのカラム(列)の情報を抜き出したい、というのはよくあるシチュエーションなのですが、その際にカラムを指定して情報を取りだす方法が2通りあります。
import pandas as pd
df = pd.read_csv("sample.csv")
print(df["hoge"])
print(df.hoge)
# どちらも同じ出力("hoge"という名前のカラムの内容を出力)
df[“hoge”]にしろ、df.hoge にしろ、同じカラムの内容を取得できるということです。
もともとcsvファイルから読み込んでいることを考えると、文字列型の “hoge” という情報を、メンバ(変数)である df.hoge に自動で取り込んでいることになります。
個人的に、この「テキストデータ ⇒ 変数名」への変更をどう実現しているか分からなかったので、やり方を調べてみようと思った次第です。
なお、変数名も、その実態はシンボル名であり、突き詰めればテキストデータなので、テキストデータとシンボル名を仲介するものが何かが分かれば
テキストデータ ⇒ 変数名
への変換は実現できることが分かります。
結論を言ってしまうと、
- 組み込み関数のlocals(), globals() を使って、ローカル名前空間・グローバル名前空間に登録されている変数名を変更する
- クラスのインスタンスの場合は、obj.__dict__ に変数名をkeyとして追加する
とすることで、「テキストデータ ⇒ 変数名への変換」は自分でも実装ができます。
本文では具体的なコードを交えながらもう少し細かく述べてみようと思います。
さて、そろそろ
「御託はいいからさっさとやり方教えろ!」
的な声が聞こえてきそうなので、早速中身に入っていきましょう!
locals(), globals() を用いる方法
まず、Pythonの組み込み関数である
- locals()
- globals()
を用いる方法について解説します。
これらの組み込み関数は何か、ということですが、それぞれを解説すると以下のようになります。
- ローカル名前空間に登録されている変数名とその値を格納した辞書を返す関数
- グローバル名前空間に登録されている変数名とその値を格納した辞書を返す関数
※ Pythonには基本的にローカルスコープ・グローバルスコープの2種類しか存在しません。詳細はネット上の情報・または後日更新する記事に譲ります。
さて、locals, globals で取得できる情報の中身ですが、例を示すと以下のようになります。
import numpy as np
from pprint import pprint
def sample_function():
pass
if __name__ == "__main__":
variable1 = 10
variable2 = [1,2,3]
pprint(locals())
"""
【出力結果】
{'__builtins__': {
- 省略 -
},
'__cached__': None,
'__doc__': None,
'__file__': 'C:\hogehoge\sample_filename.py',
'__loader__': None,
'__name__': '__main__',
'__package__': '',
'__spec__': None,
'np': <module 'numpy' from 'C:\-hogehoge-\site-packages\numpy\__init__.py'>,
'pprint': <function pprint at 0x00000286C03BD4C8>,
'sample_function': <function sample_function at 0x00000286C0D10B88>,
'variable1': 10,
'variable2': [1, 2, 3]}
"""
locals, globalsの出力結果は辞書として返ってきます。
まず、出力にある __builtins__は組み込み関数に関する情報が格納されています。
その他、アンダースコアで囲まれているkeyに関しては特殊メソッド・特殊フィールドの情報が格納されています。
それらを除いた残りのkeyについて見てみると、インポートしてきたnumpyの情報は”np”をkeyとしていることが分かる他、変数 “variable1”, “variable2″もkeyとして存在しており、スクリプト中で代入した値が value の部分に格納されていることが分かるかと思います。
また、スクリプト内で定義されている関数 “sample_function” についても、その実体がアドレス「0x00000286C0D10B88」に格納されていることが明記されています。
さて、本題の「テキストデータを変数名に変換する」についてですが、locals, globals で取得できる上記の辞書に情報を追加してやればOKそうだということが分かります。
ということでこれも早速サンプルコードで確認してみましょう!
※ 公式マニュアルによるとこの辞書は操作するなということです。試すときは自己責任で。
from pprint import pprint
ns = locals()
ns["hoge"] = "value"
print(hoge)
pprint(locals())
"""
【出力結果】
value
{
-省略-
"hoge": "value"
}
"""
必要な部分しか抜き出していませんが、出力結果の辞書を見ると “hoge”というkeyに対して “value” という文字列が格納されていることが分かります。
また、スクリプト内で hoge = “value” としていないにも関わらず、hogeというシンボル名で”value”という文字列にアクセスできていることが分かります。
これでstringとして格納されているデータを変数名とすることが可能と分かりました。やったね!
※ 前述の通り非推奨な操作なのでやるときはくれぐれも自己責任でお願いします。お兄さんとの約束だぞ!?
クラスのインスタンスの場合
導入でも触れましたが、そのオブジェクトの __dict__ メソッドを呼び出してくることで「テキストデータ ⇒ 変数名」への変換ができます。
pandas の DataFrame ではこちらを用いているはずです。
では早速サンプルコードです。
class SampleClass:
def __init__(self):
pass
sc = SampleClass()
sc.__dict__["hoge"] = "value"
print(sc.hoge)
"""
【出力結果】
value
"""
何もしないSampleClassを定義し、その中に”hoge”というメンバ変数を追加しています。
確かにクラスの定義では存在しない変数を後から追加できていることが分かるかと思います。
まとめ
今回の記事では、Pythonにおいて「テキストデータ(string)」を「変数名」に変換する方法についてまとめてみました。
正直今回の内容はpandasのDataFrameの挙動・実装の理解がしたかっただけであり、これが分かったところで何か劇的にスキルが上がる!といった類のものではありません。
ただpythonのscope・名前空間とも関係する話なので、処理系の仕様を理解するという点においては意味があると思います。
補足としてスコープ・名前空間についてもまとめられればと考えています。
さて、短いですが今回は以上としようと思います。最後までお読みいただきありがとうございました!
コメント