俺のmacでpipがこんなに動かないワケがない

自宅のOSXにansibleを入れようとしてpython2系のpipを叩いた時、
必ずコケていたのだが、調査していなかった。

通常python3で事足りるが、ansibleはpython2が必要なため導入を試みる。
早速、コマンドを実行しよう。

# pip install ansible
OSError: [Errno 1] Operation not permitted: '/tmp/pip-Es6ZOZ-uninstall/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/six-1.4.1-py2.7.egg-info'

なんてこった。やっぱりpipがコケた。
windowsから切り替えれば乗りきれると思ってたpip地獄。
しかし、下記のブログを参照し

www.starlod.net

OS X EI Capitanで導入されたファイルロックであることを知る。

ならどうするか?

misos.hatenablog.com

pipに限った話なので今回は上記の方法を取ることに。よって

# pip install ansible -U --ignore-installed six

を実施すると、うまく行きました。

しかし、これって他のboto3, s3cmdとかpipではいるんですかね?

ためしてみるとbotoは入ったが、s3cmdは入らず。エラーの内容は特定のディレクトリ配下にshareフォルダを作れなかったから。
#ルートになってから、手動で試してもpermissionがないと言われたのでお手上げ侍。
下記コマンドを入力して気づいたが、python2をbrewでもシステムネイティブでもないものをいつの間にやら入れていた様子。

# brew doctor
Warning: Python is installed at /Library/Frameworks/Python.framework

Homebrew only supports building against the System-provided Python or a
brewed Python. In particular, Pythons installed to /Library can interfere
with other software installs.

それならいっそ消すかvirtualenvですかね。消すのは忍びないのですが。。
一旦必要な物は揃いましたのでこの辺で

やべぇ、社会人ナメてた

オペレータという職業柄か毎日がせわしない。
研究をしていた時と比べると自分の時間がほぼないという環境は新鮮だ。(嫌というわけでもない。慣れた)
問題を新たにひねり出すよりも、いかにミスなく不測の事態を乗り切るのかという問題に突き当たることが多い。
ただ、業務方法について問題提起する姿勢は持っている。
このブログの存在を忘れるほどに、サーバエンジニアライフを満喫していた。
今の僕は、物理サーバの組み立てからミドルウェアのインストールまでささっとできるようにはなったけど、
どうにも数学やその他SPIで問われるような能力は著しく低下しているようだ。
ともあれ、スキルアップを加速させていきたい次第。
今の仕事も人間関係良好で楽しいのだけれども、もっともっと向学したいね。
転職を視野にいれて動いてます。

サーバエンジニア(Webオペレータ)やってます

会社に入って色々と切磋琢磨する日々。
なにかブログの記事にできるようなものがあればと思い、
現在再開予定っす。
今後は、サーバ関連の記事になります。
まぁ、Qiitaググったら出てくるような内容なんですが、
変わった内容についても随時触れていくことができればいいなと思っております。

内包表記の表現力

  • リスト内包表記でできること

よく、pythonのリスト内包表記っていうと用例としては、

[x ** 2 for x in range(10) if x % 2 == 0]

のようなワンライナーが引っかかります。通常のfor文のように複数の処理を書くことって出来ないと思ってやってました。たとえば、

c = C()
for i in range(10):
    c.method()
    print(i)

 こんな感じのどこにでもある処理を内包表記で書けないかなっと。ただ、そうすることの意味ってあんまりないように思えるし、内包表記の中はインデントが整ってなくてもいいので、そもそもインデントが整ってるfor文の形式の方がpythonの禅にかなってるのかなとは思ってるんですが。思いついたのがこちら

>>> c = C()
>>> [[c.method(), print(i)] for i in range(3)]
0
1
2
[[Object, None], [Object, None], [Object, None]]

ああ、そうかたったこれだけで済んだんだ。けどこういう書き方見かけないなぁ。(レベルの低いこと言ってたらすいません)とりあえず、メソッドや組み込み関数が返す値がリストに入る。

>>> c = C()
>>> [[c.method(), print(i)][0] for i in range(10)]
0
1
2
[Object, Object, Object]

いらない値は抜き取ることも容易です。

 二つの場合でランダムウォークするシミュレーションを書いてみる。

import random

Lx = 100
Ly = 100
N = 5
T = 2

class Agent:
    
    def __init__(self):
        self.pos = dict(x=random.randint(1,Lx),
                        y=random.randint(1,Ly))
        self.min = dict(dx=Lx,dy=Ly)

    def __str__(self):
        #return str(vars(self))
        return "x: {} y: {}".format(self.pos["x"], self.pos["y"])

    def random_walk(a):
        rr = random.random()
        if rr < 1/4:
            a.pos["x"] += 1
        elif rr < 1/2:
            a.pos["x"] -= 1
        elif rr < 3/4:
            a.pos["y"] += 1
        elif rr < 1:
            a.pos["y"] -= 1
        return a

if __name__ == "__main__":
    c = Agent()
    cs = [Agent() for i in range(N)]
    #いつもの書き方
    for j in range(T):
        print("timer: {}".format(j))
        for i in range(N):
            print(cs[i])
            cs[i].random_walk()

    #インデントぐちゃぐちゃ    
    [[[print("timer: {}".format(j))],
            [[print(cs[i]),
              cs[i].random_walk()]
             for i in range(N)]]
     for j in range(T)]

インデントから逃げたら括弧の嵐になっちゃったね。

修論終わり

論文を無事書き終わることができた。
ひとえに僕を支えてくれたみんなのおかげだと思う。
僕の研究の結論は、ここではそっと胸に秘めておくとして、
研究をしていく中で改めて下記の言葉の大切さを実感している。

っと、まぁ意識高いキラキラ修士な匂いがプンプンする文面であるが、個人的には色々と思うところがあり、もう少し研究をしてみたいなっと思いつつ、残りの作業(海外論文へ投稿)は教授に任せることにした。データをくれといわれたときに吐き出す作業には協力するように言われているので、社会人になっても若干の引き継ぎは残るものの、こういうときには指導教官の偉大さを感じる次第。(まぁ、他の先生たちもホントすごい人ばっかだったけど。。。)

 あまり特定されない範囲で書くと、自分が比較的新設の大学院に入学するとなったとき、正直、あまり教育方針には期待していなかった。大体、できたばっかりなんだから好きなこと勝手にやろうと思って入った節がある。しかし、それぞれ関連が薄く、つながりが見えにくいカリキュラム(すいません)をこなしていく中で、自分の中では少なくとも点と点がつながった感触があった。きっと、この感触は他の後輩も感じると思う。そこに、論文を書けるだけの新しい形が潜んでいる気がする。

 おそらく今の時代に古典的な数学(微分幾何学とか?)を学んで成果を出すのは難しいだろう。現に僕の学部のころの微分幾何学の先生は、学ぶだけでおなかいっぱいになってる印象だった。それに比べて、計算機科学に近しい分野をやってる人は今最も楽しい思いをしているはずだ。(研究に興味があれば)

 中学生くらいの頃、歴史の教科書に載ってる中世の人の髪型を見て笑う人がいたが、僕は正直、今の時代にいる人もその人たちと変わらないと思う。自分たちが、普遍的なポジションにいると錯覚してしまいがちだが、今という限られた時代の様式に従って僕たちは生きてる。僕らの服装も時代とともに変わっていく。今の時代に反発してバッハみたいなカツラをかぶる人やちょんまげを常備整えている人はおそらくほとんどいないだろう。その時代の人たちを笑う行為は、ダブルスタンダードに近い。(大げさだなぁ

 っと、まぁ系譜学みたいなことをいってもあれなんだが、何がいいたいかというと、僕たちは、タイムマシーンがない以上、この時代を生きるしかないわけで、この時代に最適化する必要があるだろうということだ。それは、やったほうがいいと思う。(頑固な人は変えなくていいけど)そのほうがきっと今の流れに乗って先のほうまで景色が見えると思う。今まではみんなに見えなかった景色。それが、今でいうところの計算機科学、ひいてはバイオや、宇宙工学なんだろうと思う。けど、あまりにも短期的に最適化する必要はない。それこそ、今、10年前のプログラミング言語を使う人がどのくらいいるか、みんながあとどれくらいクラウドクラウド!って言ってるか、データサイエンスって言ってるかは僕にはわからないけど。そのワードを言ってる人たちは、きっとその根底にある大事なことを学んでほしいから新しいキーワードを紹介して、若い人たちを釣ってるんだと思う。だから、そういうのはきっかけであればいいし、普遍性はきっとすぐそばに横たわってると思う。(ポエム終わり

クラスにイテレータの性質を付加する

  • クラスと辞書の関係

 ちょっと前の記事で紹介したとき、pythonのクラスはデフォルトとしてイテレータとして使用できていませんでした。今回も基本的なことですが、イテレータを定義する話です。

>>> class _:
	pass
>>> list(_)
Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    list(_)
TypeError: 'type' object is not iterable

 「オブジェクトはイテレータではありません。」そうか、じゃあ定義しよう。たとえば、辞書型みたいに整形して、属性をイテラブルに呼び出したりできるクラスがほしいな。。と思っていたら、できるみたいです。

class Person:
    def __init__(self, age, sex, name, subject):
        self.age = age
        self.sex = sex
        self.name = name
        self.subject = subject

    def __iter__(self):
        for k, v in self.__dict__.items():
            yield (k,v)

if __name__ == '__main__':
    p = Person(20, "male", "John Smith", "computer simulation")
  • 実際に動かしてみた

 これでクラスの定義ができました。実際に動かしてみましょう。

>>> p
<__main__.Person object at 0x0000000003924518>
>>> p.__dict__
{'subject': 'computer simulation', 'sex': 'male', 'name': 'John Smith', 'age': 15}
>>> [i for i in p]
[('age', 15), ('subject', 'computer simulation'), ('name', 'John Smith'), ('sex', 'male')]
>>> [print(k+":",v) for k,v in p]
subject: computer simulation
sex: male
name: John Smith
age: 15
[None, None, None, None]

 クラスの属性は辞書型で保存されているようです。それを用いてジェネレータ関数を使用し__iter__を定義してみました。ジェネレータをまわすときにはyieldを使いましょう。もしreturnで定義してしまうと

#変更したクラスの箇所
def __iter__(self):
	for k, v in self.__dict__.items():
		#yield (k, v)
		return (k, v)
>>> [i for i in p]
Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    [i for i in p]
TypeError: iter() returned non-iterator of type 'tuple'

 イテレータではなく、普通にタプルを返すので、イテレータをちゃんと返せとエラーが返ってきます。

  • そもそも論

 初めから__iter__や__dict__があるならあるいはもっと基本的な__iter__, __dict__の定義があるんじゃないだろうか。そうなんです。たとえば、これだと

class A:
	def __init__(self,x,y):
		self.x = x
		self.y = y
>>> a = A(1,2)
>>> a
<__main__._ object at 0x000000000376EE48>
>>> a.__dict__
{'y': 2, 'x': 1}

 辞書はもともと入っているので、先ほどのようにイテレータを定義せずとも辞書は出せたわけです。当たり前といえばそうなんだけど

>>> help(a)
Help on A in module __main__ object:

class _(builtins.object)
 |  Methods defined here:
 |  
 |  __init__(self, x, y)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

 ヘルプにもちゃんと初めから書いてあるし。。じゃあ、__iter__はあるのかというと

>>> help(a.__iter__)
Traceback (most recent call last):
  File "<pyshell#97>", line 1, in <module>
    help(a.__iter__)
AttributeError: 'A' object has no attribute '__iter__'

 ない。だったら、書けばいいのだが、iterだけを用意したらいいのかというとそうでもなくて、next()関数を定義してやることで正常に動かせるようです。

(引用)
Pythonの技法:ジェネレータを用いた遅延リストの構築 - builder by ZDNet Japan
Python のジェネレータ (1) - 動作を試す | すぐに忘れる脳みそのためのメモ
Python のイテレータ (3) | すぐに忘れる脳みそのためのメモ
エキスパートPythonプログラミング(1) イテレータ、ジェネレータ、ジェネレータ式 - 作業記録/備忘録(仮)
Pythonのイテレータとジェネレータ - Qiita
ジェネレータ (プログラミング) - Wikipedia