Hatena::Groupbugrammer

蟲!虫!蟲!

Esehara Profile Site (by Heroku) / Github / bookable.jp (My Service)
過去の記事一覧はこちら

なにかあったら「えせはら あっと Gmail」まで送って頂ければ幸いです。
株式会社マリーチでは、Pythonやdjango、また自然言語処理を使ったお仕事を探しています

2011-12-16

[] "is" is not "==" -- Pythonにおける"is"と"==" 23:49

 さて、Pythonには「is」と「==」という、二つの演算子があるのですが、今回はその話題にふれてみようと思います。というのも、『はじめてのPython』を読み直してみると、「"=="は同値のもの、"is"は同一のもの」という風に書かれていたからです。Pythonにおいて、同一と定義されるものは、それが同じインスタンスであるかどうか、ということです。もう少し言うと、「メモリ上の同じアドレスに存在する同一のオブジェクトであるか」ということです。

 Pythonにおいては、変数は単に「オブジェクトへの参照を格納しているモノ」なわけです。だから、例えば

>>> a = "a"
>>> b = "a"
>>> a is b
True

 となるわけです。「何を当たり前のことを」と思うでしょうが、次の挙動を見て同じことが言えるでしょうか?

>>> [1,2,3] is [1,2,3]
False
>>> (1,2,3) is (1,2,3)
False

 あれ、明らかに一緒なのにおかしい……といったように、文字列や数字の場合、一回そのオブジェクトを生成して、それを使いまわししているので、isで比較したとしても、「メモリ上の同じアドレスに存在する」ことになります。しかしリストやタプルなどの配列みたいなものは、いちいちインスタンスを作っているので、「同一じゃねーな」ということになります。実際に、id()という関数によって、そのオブジェクトの番号について調べることができます(要するに hoge is fuga は、id(hoge) == id(fuga) と書き直すことができます)。

 実は、PythonのPEP8でも、「Noneかどうかを調べるときは"is"を使えボケ」と書いてあります。他のブログ記事をちらっと見た限りだと、一つ限りのオブジェクト(Trueとかその辺)は、"is"を使うと正確になる、という話があります。

>>> 1 == True
True
>>> 1 is True
False

 Pythonの場合、Trueの値は1なので、「==」で比較するとTrueになります。実際にTrue + Trueすると2が返ってきたりします。なので、正確にBool値におけるTrueを取り出したいときは"is"を使います。もう少しポイントになるのは、「==」は、メタプログラミング的に「__eq__」というメソッドを呼び出します。例えば、次のようなClassを実装してみます。

>>> class NoneisTrue:
...     def __eq__(self,other):
...             return True
... 
>>> none = NoneisTrue()
>>> none == None
True

 ここでわかるのは、「==」というのは、あくまでも__eq__の実装がどのようになっているのかによるのであって、必ずしもNoneと同じ値であるかどうかを調べているわけではないわけです。そもそも、同じ値かどうかという定義自体をプログラムの中で行っているわけです。なので、実装的にも、速度的にも、isで比較していたほうが安心というわけです。

 ところで、Noneについては比較が使えるようで、下のような比較も使えたりします。

>>> None < False
True

 Noneはif文に投げればFalseとして扱われますが、Falseは、値としては0なので、

>>> False < -1
False

 というところは面白かったりします。この辺、ちょっと頭の隅においておくといいかなと思ったりしました。

参考

python - Is there any difference between "foo is None" and "foo == None"? - Stack Overflow

doloopwhiledoloopwhile2011/12/21 12:38細かい話になってしまうのですが、文字列の is と == は必ずしも同じ結果にならない場合があります。
>>> a = "a"
>>> b = "a"
>>> a is b
True
が成り立つのは、aとbが同じモジュールに定義されていて、値の"a"がキャッシュされているからですが、

値が動的に生成されていると
>>> a = "a" * 2**10
>>> b = "a" * 2**10
>>> a is b
False
となってしまいます。

AlexandraAlexandra2012/02/29 13:41Stelalr work there everyone. I'll keep on reading.

figdekfigdek2012/03/01 18:094OTvxK <a href="http://jsuyyqkoquol.com/">jsuyyqkoquol</a>

qujtjhtakuqujtjhtaku2012/03/11 14:21S8NH6k <a href="http://nqbzhrucpbng.com/">nqbzhrucpbng</a>

yyihqnhtyyihqnht2012/03/14 22:206lCxJ4 , [url=http://dhockwdxnmdb.com/]dhockwdxnmdb[/url], [link=http://kualjkvrzglh.com/]kualjkvrzglh[/link], http://zyeafneuphow.com/

2011-12-15Python Advent Calender(全部俺):: 15日目

[]リスト内包記法だけで素数を取り出す -- Pythonにおけるリスト内包記法について 17:17

 今回はさらっとリスト内包記法について。

 例えば、素数配列をリスト内包記法で取り出す場合は、次のように一行で書けたりします。(引用 : Python List Comprehension for Prime Numbers - xkcd)

[prime for prime in range(2, n) if prime not in [notAPrime for i in range(2, int(n**0.5)) for notAPrime in range(i * 2, n, i)]]

 これだと、何をやっているのかさっぱりわからないので、もう少し素直に書き直してみましょう。

[c for c in range(1,1000) if True not in [(c % isPrime == 0)for isPrime in range(2,c)] ]

 まず、最初の"if hoge not in"なのですが、実はinというのは演算子だったりします。どういう演算子かといえば、リストの中にある要素が存在するかというのを調べることができます。例えば、下のように書けたりします。

(1 in [1,3,5])

 リスト内包記法の中でifが使われる場合、そのifの要素がTrueの場合のみ、リストの中に追加されるという挙動をするようです。例えば、次のように。

[c for c in range(1,100) if c % 2 == 0]

 なので、一番目の奴(自分が書き直していないもの)においては、素数ではないリストを作ってあげています。

 ただ、書き直していて気がついたのですが、どうやらリスト内包記法において、forで宣言されている変数のスコープは全体で適用されているようです。

[[a for a in range(c)] for c in range(10)]

 なので、自分の書き直したものでも、ちゃっかりcはリスト内包記法内の、リスト内包記法でも適用されます。二番目のリスト内包記法は、値で割りきれたかどうかのリストです。素数の場合、とりあえず「割りきれたかどうか」が重要なので、数値にはこだわりません。次に、このリスト内包記法の中に"True"が存在するのならば、それは素数ではないので、使わないようにします。

 ちなみに、Pythonの仕様として、[]や()の中では、改行が使えたりします。なので、一行で見にくいなーと思ったら、下のように改行しても通るみたいです。

[c for c in range(1,1000)
    if True not in
        [(c % isPrime == 0) 
        for isPrime in range(2,c)]]

 リスト内包記法も、Pythonにおける読みにくくする記法の一つだったりするのですが、頭の体操によかったりするので、リスト内包記法だけで書けるフィボナッチ数列など、いろんなリストの生成をどうしたらリスト内包記法で書けるのか、ということに挑戦してみるといいかもしれません 。

MarietaMarieta2012/02/28 03:52If not for your wirtnig this topic could be very convoluted and oblique.

goufzggoufzg2012/02/28 17:13NshjmY <a href="http://mxiepmwhrrvh.com/">mxiepmwhrrvh</a>

zdkizlbpizdkizlbpi2012/03/02 03:03BCOsKX <a href="http://ffryekuuitbd.com/">ffryekuuitbd</a>

dubczafdubczaf2012/03/14 11:51Ojs0eB , [url=http://zrqpxnslkgup.com/]zrqpxnslkgup[/url], [link=http://rpyllsawmmvb.com/]rpyllsawmmvb[/link], http://obaucofqkxhz.com/

2011-12-14Python Advent Calender(全部俺):: 14日目

[]僕たちPythonistaは、ちょっとしたコード生成にPythonを使います! -- 休憩:Pythonによるクリップボードの扱い方 23:25

 404 Blog Not Found:javascript - めんどうな作業がわずか1クリックに!新人プログラマーが知らないと一生後悔するブラウザーを使ったHTML生成

 DanさんだったらPerlワンライナーでコマンドを走らせたら自動整形してくれるようなコードを書くような気がしたけど、ちょっと違った(偏見は良くないね)。なのでPythonで書いてみることにする。ワンライナーで。

import gtk;i=" "*4;exec('def f():\n'+i+'r=[]\n'+i+'for line in gtk.clipboard_get().wait_for_text().split("\\n"):r.append("\\n<tr>\\n"+"".join(["'+i+'<td>%s</td>\\n"% el for el in line.split("\\t")])+"</tr>")\n'+i+'return r');print "<table>","".join(f()),"\n</table>"

 Python で手っ取り早くクリップボード操作を行う (暫定) - 何にしても生っかじりの朴念仁を参考にしてみたけれども、自分のUbuntuの環境が悪いのか、gtk.set_textを使おうとすると、見事にクリップボードの中身がクリアされるしかないというよくわからない状態になっていたので(一応、gtk.store()もしてみたんだけど)、printで吐き出すという妥協をすることにした。GUI系のライブラリは、こういうちょっとした作業をするときに便利だったりするので、チェックしておくと損がないのかなあ、という気はした。

TonyaTonya2012/06/09 23:24Thuhgot it wouldn't to give it a shot. I was right.

edlmrpyjbedlmrpyjb2012/06/10 19:59KtM8Lf <a href="http://vtorodpdoklr.com/">vtorodpdoklr</a>

buvtbdlnlxlbuvtbdlnlxl2012/06/11 10:263xVtdg , [url=http://vmybcapoqlcj.com/]vmybcapoqlcj[/url], [link=http://ykmetxgckakp.com/]ykmetxgckakp[/link], http://zjcchohtrdbx.com/

fdaewxoxkfdaewxoxk2012/06/13 01:38gwgWXm <a href="http://sqwnpdabvbio.com/">sqwnpdabvbio</a>

2011-12-13

[]お前は何者かは興味が無いが、お前の力を借りたい -- Pythonにおけるポリモーフィズム 00:40

 というわけで、今日のネタはポリモーフィズムについてのメモです。というのも、以前にモナドを自分なりに実装してみたのですけれども、その実装をしているうちに、「あれ、これってポリモーフィズムを破壊していることになっているんじゃないか」と気がついたからでした。

 ポリモーフィズムについては多態性と呼ばれています。『はじめてのPython』によれば、「1 + 1」は数字の追加になるわけだし、「"hoge" + "hoge"」ならば文字列の連結になります。このように、オブジェクトの種類によって、機能が変わってきます。そして、その関数が使えるかどうかは、決まった呼び出し方に対応しているかどうか、ということがポイントになってきます。

演算子オーバーロードする

 このあたりに関しては、抽象的に考えるより、実際にコードを書いてみるほうが早いと思うので、演算子オーバーロードから、その当たりを考えてみたいなと思います。例えば、次のようなことをやってみましょう。

>>> class Hoge:
...     pass
... 
>>> hoge = Hoge()
>>> hoge + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'instance' and 'int'

 そりゃエラーが出るのは当たり前です。明らかに数字じゃないものを足しているわけだから。でも次のように書いてみるとどうでしょうか。

>>> class Hoge:
...     def __add__(self,other):
...             return "hoge" * other
... 
>>> hoge = Hoge()
>>> hoge + 1
'hoge'
>>> hoge + 3
'hogehogehoge'

 なんと、オペレーターに対応しましたね。

他の言語のポリモーフィズム

 そこで、Pythonポリモーフィズムに直接触れるよりも、他の言語のポリモーフィズムについて調べてみましょう。例えば、『独習Java』には、明確に「一つのインターフェイスに複数の実装」というのをポリモーフィズムと述べています。例えば、こういうソースが掲載されているので、それを引用してみましょう。

abstract class Hoge{
    abstract int returnSomething();
}

class Fuga extends Hoge{
    int returnSomething(){
        return 4;
    }
}

class Poko extends Hoge{
    int returnSomething(){
        return 3;
    }
}

 さて、これがJavaにおけるポリモーフィズムの実例なのですが、これの何が嬉しいのか。というのも、ある変数が、どのクラスのインスタンスかわからないことが往々にしてあるからです。例えば、eseharaは、場合によってはnew Fugaかもしれないし、あるいはnew Pokoかもしれません。しかし、ポリモーフィズムを導入することによって、「別にどっちでもいいじゃん」と言えるわけです。実際に、次のようにも書けるわけです。

class PractiseJava2 {
    public static void main(String[] args) {
        Hoge esehara = new Fuga();
        esehara = new Poko();
        System.out.println(esehara.returnSomething());
    }
}

 つまり、そのメソッドが呼び出せれば、どっちでもいいだろボケ、というのがポリモーフィズムなのかな、と思います。

そしてダックタイピングへ

 さて、いきなりJavaの話を持ち出したのは他でもなく、『はじめてのPython』に、次のような話が出てくるからなのでした。

 Python関数にこのような特性があるということは、C++Javaといった言語(引数戻り値などの型があらかじめ固定される言語)とは、関数を作る際の発想をまったく変えなければならない、ということです。Pythonでは、特定の型を想定して関数のコードを書くべきではありません。もし特定の型を想定してコードを書けば、関数の応用範囲がそれだけ狭まることになります。

 もちろん、型を用意するということは、予期しない入力などを最小限にしてくれるメリットはあるのですが、同時に柔軟性も失われます。特にPythonの場合だと、その型というより、型が持つインターフェイスのほうが重要だったりします。例えば、タプルとリストは型としては違うものですが、インターフェイスは一緒です。なので、下のように簡潔に書けます。

>>> a = (1,2,3)
>>> b = ["a","b","c"]
>>> for j in (a,b):
...     x,y,z = j
...     print x + y + z 

 極端に型をごちゃまぜにしてみましたが、無事処理してくれます。

 さて、インターフェイスにこだわるという意味では、ダックタイピングという考え方があります。ダックタイピングとポリモーフィズム - みねこあの記事が参考になったので、ここを参考にしながら考えてみましょう。

ダックタイピングにおいては実行時に実際に呼ばれたメソッドのみが実装されていればよく、一方でテンプレートではコンパイル時にアンリーチャブルであると証明できなかった全てのメソッドを実装する必要があるため、ここでもダックタイピングはよりフレキシブルとなれる。

 ポイントは、「呼ばれたメソッドが実装されていればよく」という部分でしょう。つまり、そのオブジェクトが「ところでお前は何ができるの?」ということにしか興味がなく、そのオブジェクト自体はどうでもいいわけです。「ガー」と鳴くんだったらカエルだろうがアヒルだろうがなんでもいいわけです。

>>> class Dack:
...     def goo(self):
...             return "Goo!!"
... 
>>> class Flog:
...     def goo(self):
...             return 100
>>> for Something in (Dack,Flog):print Something().goo()
... 
Goo!!
100

 よく、目隠しをした人間が、象の身体を触って、各人が勝手な推測を立てている絵、というのがよく引用されていますが、むしろその全体像は特別知る必要はなく、そのメソッドがあるのかどうか、というところがポイントであると言えるでしょう。もちろん、あるときには文字列、あるときには数字というのはたまったものじゃないわけで、一長一短といったところなのかなという感じです。

過去の関係あるかもしれない記事

PngからDivを吐き出すページを作った - 蟲!虫!蟲! - #!/usr/bin/bugrammer

NathaliaNathalia2012/02/27 16:47Begun, the great internet edcutaion has.

ohkolvvdzxrohkolvvdzxr2012/02/28 04:23yzxKin <a href="http://hbxfkojebaew.com/">hbxfkojebaew</a>

rvrpcytgyrtrvrpcytgyrt2012/03/01 23:28U11XE4 <a href="http://tjohexuovvar.com/">tjohexuovvar</a>

sojwdyglfsojwdyglf2012/03/14 11:02CZ6QQU , [url=http://vxenxweyawnz.com/]vxenxweyawnz[/url], [link=http://kyogbiuuwuxq.com/]kyogbiuuwuxq[/link], http://yupydfiovkjs.com/

2011-12-12Python Advent Calender(全部俺):: 12日目

[]過去に使ったことのあるライブラリをまとめて紹介する 20:50

 今日は簡単に、過去に色々といじったライブラリの紹介を軽く。

Pygame

 no title

 言わずと知れたSDLライブラリ……なんだけど、使いこなすと結構幅が広がることで有名。別名・マルチメディアライブラリ。例えば、過去の記事において、CDドライバを開いて、メールのアラートに使ったりしていた。また、画面を生成したあとに、"pygame.image.save"を使ったりするといいかもしれない。Pure Pythonを求めるならば、別にPyglatというものがある。

 ちなみに、Game関係で言うならば、iphone用のゲームライブラリであるcocos2dの元はPythonだったりするんだけれども、機能的にはかなり大差をつけられている、という書き込みがあったりして少し悲しいことになっている。

 なお、書籍も発売されていて、なかなか人気が高い。

Selenium

 mitszoの日記

 過去にMechanizeを紹介したのはいいんだけど、Mechanizeの欠点はJavaScriptを読み込んでくれないことです。だけどJavaScriptの挙動をそのままPythonに持ってくるのは現実的ではないので、ブラウザを起動して、そこから操作させてしまうのが一番いい。というのわけで、Seleniumというドライバを使うと、その辺は幸せになる。ただ、モノによってはPythonを使うよりもRubyのほうがちゃんとした挙動を取ることがあるので、その辺がちょっと難しいところ。

Paycheck

 Python3 の関数アノテーションを使って自動テストする - forest book

 本当は、テストのことでも書こうかなと思っていて見つけたんだけど、先に紹介をされてしまっていて、ネタ被りはさすがに恥ずかしいので、急遽方針を変更することに。説明も、こっちのほうが上手いし。PayCheckは、元はといえばHaskellのQuickcheckと呼ばれる、テストデータの生成と、そのテストデータを加工したときの評価を自動的に行ってくれるライブラリに発想を得ている。doctestと共に書いていきたいテストの一つ。

Mecab

 Error 404 (Page not found)!!1

 形態素解析をしたいのならば、このライブラリ。過去の記事にもちょくちょく出てきました。

PyQt

 PyQtではじめるGUIプログラミング

 GUI部分を作ったりなど、いろいろなことが可能な総合ライブラリ。過去にはHTMLPDFに吐き出すために使用。いろいろなことが出来そうな気はしている。

Flask

 Bitbucket | The Git solution for professional teams

 とにかく簡単にWebアプリケーションでデモを作りたいならこれを使う。Djangoみたいに大きなシステムはいらないけど、だからといって一から作るのは面倒くさい、という中間点を生めてくれる。お手軽。

Yacc+Lex

 PythonのLex + Yaccでオリジナル言語を作るための第一歩についての覚書 - 蟲!虫!蟲! - #!/usr/bin/bugrammer

 パーサーの勉強がてらに使っている。LR法で、もっともメジャーなパーサージェネレーター。もう一つの有名なパーサージェネレーターにpyparsing - homeというのがある。