Python __repr__ と __str__の違い

Pythonの関数で、アンダースコア2つ __ (←これ) で囲まれている関数を、特殊関数と言います。特別な役割があります。

__repr__ と __str__ってどう違うの??といつもわからなくなってしまうので、メモしておきます。

 

下記のPython3の公式ドキュメントによると

https://docs.python.jp/3.3/reference/datamodel.html

object.__repr__(self)

repr() 組み込み関数によって呼び出され、オブジェクトを表す「公式の (official)」文字列を計算します。

object.__str__(self)

オブジェクトの「非公式の (informal)」あるいは表示に適した文字列表現を計算するために、 str(object) と組み込み関数 format(), print() によって呼ばれます。

だ、そうですが。

なんやねん。公式とか非公式とか!!って思いますよね。

とりあえず、動作を見てみます。

class MC():
  def __repr__(self):
    return 'Wahaha!'

  def __str__(self):
    return 'Uki'


mc = MC()
print(mc)

上記の出力結果は

Uki

となります。

class MC():
  def __repr__(self):
    return 'Wahaha!'

  def __str__(self):
    return 'Uki'


mc = MC()
print(str(mc))

上記の出力結果も

Uki

となります。

__str__関数がない場合は

class MC():
  def __repr__(self):
    return 'Wahaha!'

mc = MC()
print(str(mc))

__repr__が使われて、

Wahaha!

が出力されます。

 

下記のサイトさんによると、次のような動作です。

http://taustation.com/python3-str-repr/

print文やformat文での__str____repr__の使われ方は次の通り。

  • __str__のみが定義されていれば__str__が使われる
  • __repr__のみが定義されていれば__repr__が使われる
  • __str____repr__の両方が定義されていれば__str__が使われる

Python 再帰関数 初めの一歩

再帰関数 超むずい。

ファミマの焼き鳥 超うまい。(食べたことないけど)

というわけで、再帰関数について勉強中であります。

 

今まで、縁がなかったんですよ。作る必要なかったっていうか。

しかし、ディープラーニング系だと結構出てきますよね!

こちらのサイト拝見して勉強させて頂きました。m(_ _)m

http://www.geocities.jp/m_hiroi/light/pyalgo01.html

とりあえず、ここに載っているフィボナッチ関数の簡単なバージョンを作ってみます。

def fibo(n):

    print('nだよ %s' %n)
    if n == 0 or n == 1: return 1

    return fibo(n - 1) + n

v=fibo(5)
print('vだよ %s' %v)

結果は次の通り。

nだよ 5
nだよ 4
nだよ 3
nだよ 2
nだよ 1
vだよ 15

再帰関数初心者としては、return が最後しか返ってこないのが不思議。

弊社の俊英 Nくんが教えてくれたのですが、
「まずは再帰の中をぐるぐるやって、終わった時にreturnします。」
だそうです。

もうちょっと飛躍させて、次のようなのを作ります。

print('はじまり')
array = [1,2,3]

def search(s):

    print("sだよ %s" %s)

    if s not in array:

        v = s + 10
        print("途中で帰るv %s" % v)
        return -v

    next_s = s + 1

    v = search(next_s)

    print('最後まで行ったv:%s s:%s' %(v,s))

    return -v

for x in range(5):
    value = search(x)
    print("vだよ %s" %value)

print('おわり')

出力は次の通り。

はじまり

sだよ 0
途中で帰るv 10
vだよ -10
sだよ 1
sだよ 2
sだよ 3
sだよ 4
途中で帰るv 14
最後まで行ったv:-14 s:3
最後まで行ったv:14 s:2
最後まで行ったv:-14 s:1
vだよ 14
sだよ 2
sだよ 3
sだよ 4
途中で帰るv 14
最後まで行ったv:-14 s:3
最後まで行ったv:14 s:2
vだよ -14
sだよ 3
sだよ 4
途中で帰るv 14
最後まで行ったv:-14 s:3
vだよ 14
sだよ 4
途中で帰るv 14
vだよ -14

おわり

最後まで行ったv というのが結局returnされないのは、さっきのくだりで学習したのですが、初心者にとって解せぬポイントは

最後まで行ったv:-14 s:3
最後まで行ったv:14 s:2
最後まで行ったv:-14 s:1

なんですよ。

なんで、これ、sの順番が逆なの??
sは 1,2,3 の順じゃないの??

これも、弊社の俊英かつサイキッカーのN君が教えてくれました。

「再帰関数は、枝分かれしていって評価するんですが、最後の枝までいったら逆順に評価していくんです。」

エッッ そうなんだ。( ゚Д゚) むずかしー!!

サイキッカーへの道は遠いようです。

Pycharm デバッグできなくなる

私はPythonの開発をPycharmというIDEで行っていますが、まだあんまり全貌がつかめていません。Pycharmは2017.3 Communitu Editionです。

特に、実行環境を適当にやっていると、おかしくなります。(適当だから仕方ないね…。)

今日はデバッグできなくなるという事態に遭遇しました。

そんな時は、ここを確認してみてください。

File→Settingus→Project Interpreter

でPythonの実行環境が選べますが、ほかのプロジェクトの実行環境を選んでないでしょうか?

そうすると、実行はできるけれどもデバッグできないようです。

では、今やっているプロジェクトの実行環境を作る方法です。

①File→Settingus→Project Interpreter って選択した後、下記の画面の赤丸の部分をクリックします。

②Add Localを選択します。

③New environmentを選択します。

Base InterpreterでPythonの実行環境を選んでください。

すると、上のLocationのところに、今選択しているプロジェクトの名前+venv という形でパスが自動的に入ると思います。

④OKをクリック

 

Python ArgumentParserでコマンドラインから実行時に強制的に引数を渡させる

きっと書いておかないと忘れるので書いておきます。

ArgumentParserという便利なライブラリがあります。

公式サイトはこちら。

平たく言うと、コマンドラインから

python main.py

って走らせるときに、引数がないと動作しないようにする、とか、ヘルプを表示させたりとか、コマンドラインの引数に応じて、実行することを変えたりすることができるのです。

超シンプルな使い方は下記のようにします。

import argparse

parser = argparse.ArgumentParser(description='Process some integers.')

parser.add_argument('integers', metavar='N', type=int)

args = parser.parse_args()
print(args.integers)

コマンドラインから引数なしで実行すると、次のように表示されます。

 

G:\test>python argparse_sample.py
usage: argparse_sample.py [-h] N
argparse_sample.py: error: the following arguments are required: N

引数を渡すと、次のように引数が表示されます。

G:\test>python argparse_sample.py 5
5

Open AI Gym 初めの一歩

強化学習というのは、機械学習の一つの分野ですが、学習がうまくいっているのかどうか調べるのは難しい課題なんですよね。

そこで、Open AIのGymというツールがあります。

https://gym.openai.com/

なんか、ちょいちょい見る、トンカチみたいなのがゆらゆら揺れてる動画…。これだったんだw

やり方は、次のサイトにある通りですが

https://gym.openai.com/docs/

英語を読むのも「ええい!面倒!!」ということもあると思いますので、超簡単に記載しておきます。

pip install gym

でインスコします。

import gym
env = gym.make('CartPole-v0')
env.reset()
for _ in range(1000):
    env.render()
    env.step(env.action_space.sample()) # take a random action

これで走らせてみると、トンカチが一回転して、画面の外に消えちゃいますねw

他に、山を登る車、

'MountainCar-v0'

ってのもあります。さっきのgym.makeの中身を変えるだけです。

import gym
env = gym.make('MountainCar-v0')
env.reset()
for _ in range(1000):
    env.render()
    env.step(env.action_space.sample()) # take a random action

これも実行してみると、右往左往してまったく山を登りそうにない車が表示されます。
やはり、ランダムに何かを行ってみても何も結果は得られない… という人生の教訓を得た気になりますね!!

ちょっと進めて下記のようにします。

import gym
env = gym.make('CartPole-v0')
for i_episode in range(20):
    observation = env.reset()
    for t in range(100):
        env.render()
        print(observation)
        action = env.action_space.sample()
        observation, reward, done, info = env.step(action)
        if done:
            print("Episode finished after {} timesteps".format(t+1))
            break

実行すると、ポールが倒れたり、画面の外に行ったりしません。

一瞬おお!と思いますが、落ち着こう。

 

observationというのをprintするようにしたので、次のようにprintされますが

[-0.06550298 -0.62622142 0.12089567 0.99951833]
[-0.07802741 -0.82273366 0.14088604 1.32759199]
[-0.09448208 -0.62964272 0.16743788 1.08210892]
[-0.10707494 -0.4370784 0.18908006 0.846299 ]
[-0.1158165 -0.24496922 0.20600604 0.6185299 ]
….
Episode finished after 16 timesteps

そもそも、この4つの数字なんだ!って話ですよね。

この答え、CartPoleのソースコード見ると書いてありました。(他のところにもかいてほしぃ…)
https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py

Observation:
Type: Box(4)
Num Observation Min Max
0 Cart Position -4.8 4.8
1 Cart Velocity -Inf Inf
2 Pole Angle -24° 24°
3 Pole Velocity At Tip -Inf Inf

そして、そもそも終了条件ってなんなん??

って思うと、これもソースコード見ると書いてありました。

Episode Termination:
Pole Angle is more than ±12°
Cart Position is more than ±2.4 (center of the cart reaches the edge of the display)
Episode length is greater than 200
Solved Requirements
Considered solved when the average reward is greater than or equal to 195.0 over 100 consecutive trials.

1.ポールの角度(さっきのObservationの3つ目ですね)が±12を超える
2.カートのポジション(さっきのObservationの1つ目ですね)が±2.4を超える
3.エピソードの長さが200以上
4.解決されたと思われる 平均的な報酬が100回の連続したトライアルの中で195を超える

報酬は、1回進めて、倒れなかったら1もらえるので、200回エピソードを繰り返して、195回目まで倒れなければ、そのモデルが優秀ということで、もうOKってことなんですかね。

Actionは左に行くか、右に行くかだけですが、これにVelocityなどが加わって、どのぐらいのポジションを進むかが決定されるようです。

倒れなくなったように見えますが、そうではなく、倒れようとしたところで(doneがTrueになる)env.resetされるので、倒れなくなったように見えるだけです。