(function(){...})()は、
(function($){
$.hoge = function() { };
})(jQuery)
みたいに使われていたりするコード。GreasemonkeyとかjQueryのプラグインとか、あれこれ見かけることがあると思います。
この話題はいくつかWebでも取り上げられていますが何がどうなってんのかちょっと難しいですね。しかし、誰でも理解できるレベルではあります。というのも、こういう種の難しさは体系的な知識が備わっているか否かということなのです。
でも、この知識を体系化する作業って結構しんどくて、難しくて、まーハゲるほど悩むこともあるかもしれない。それはきっと、とても毛根に悪いかもしれない。スカルプDも真っ青の状況になるかもしれない。それは、悲しいことなのだと思う・・・っ!
毛根にはこれからもがんばってほしい!いつだって頭を温かいまなざしで見守ってて欲しい!そうだろ!だって、だって毛根だもん!毛根が頭から離れたら何になるのさ!井手らっきょになるのさ!?
いやだいやだ、ニコラス・ケイジやブルース・ウィリスならまだしも井出らっきょだけはいやだいやだ。やめておくれよハゲの神様。井手らっきょだけは、井手らっきょだけは・・・・・・ちょっといいかも(ポッ
そんな切ない即時関数の話。じゃなくて。普通の即時関数とそれに関係する言語仕様の話。
(function(){...})()の名前
その前に名前の話。
今まで(function(){...})()というコードには名前が定まっていませんでした。(個人で好きなように表現していた→"即実行関数"や"使い捨て関数"や"自己実行関数"などいろいろ)
個人的には(function(){...})()に対して名前を統一すべきだろうなあと思っていたところ、JavaScriptパターン ―優れたアプリケーションのための作法 で「即時関数」と名付けされてい
るようです。
権威のある書籍に記述されているのであれば認知されやすいし、言葉としても分かりやすいのでこれからは即時関数という名が広まると良いですね。共通のイメージが持てれば会話にも出し易いし、検索もできますから。
タイトルや冒頭で既に使っていますが、以降から(function(){})()のことを即時関数とします。
※文中の用語について補足していただきました。ありがとうございます。
JavaScriptの関数(ラムダ関数とかクロージャーとか) - hogehoge @teramako
即時関数(function(){...})()ができること
即時関数は関数定義と関数呼び出しをまとめて行うことができるコード。
それを理解するためにまず普通の関数をおさらい。
function hoge() {
alert(1);
}
これが関数定義。(正確には関数定義の関数宣言にあたる)
当然ですが関数は呼び出さないと何もおきません。呼び出すとは言い方を変えると「実行する」ってことです。じゃあ実行します。えいや。
function hoge() {
alert(1);
}
hoge(); // 1
これが関数の呼び出し。定義した関数名の後ろに関数呼び出しの( )をつけます。さもありなん、みなまで言うなとパンチの構えはやめていただきたい。真剣なのです。
真剣に井手らっきょの進退についうぼげはぁあああ三○))゜д゜((○三
・・・えーfunction hoge( ) {...}が関数定義、hoge( )が関数の呼び出しにあたることを意識したうえで次。
関数は基本的に以上の段取りで利用するのですが、即時関数だとこれらをまとめて行なうことができます。
function hoge() {
alert(1);
}
hoge(); // 1
// 上記の関数定義と関数呼び出しをまとめて書くと↓
(function hoge() {
alert(1);
})();
見た目がなんかカッコの化けものになっちゃいましたが、それについては後述。
そういうわけで、即時関数とは、
関数定義
関数呼び出し
の2つをまとめて行なうことができるものです。
それで、このように1回実行するだけのケースだと、
(function() { // ←hogeっていう関数名は無くてもいい
alert('教頭の頭ははっちゃけている');
})();
hogeという関数名をのぞいて無名関数(匿名関数とも言われている)で呼び出すのが一般的。多くの人が見たことあるのはこちらの無名関数でしょう。
再帰的に扱うケースやデバッグといった目的があれば名前をつけたりしますが、基本的に1回ぽっきりの野郎なんざぁ名前なんてどうでもいんだよふははは!ということで無名です。
「JSerの人たちは冷酷だよ。いつだって私たちを使い捨てなのさ。一回ポッキリで女ったらしあるいは男ったらしなんだよJserは。あううう。」
という嘆きを即時関数は利用されるたびに叫んでいることを我々は常に心にとどめておくことが大切です。どうでもいいです。
ともかく、このように即時関数は関数定義と関数の呼び出しをまとめて書ける非常に使い勝手の良いコード。
カッコのばけものな即時関数も関数定義と関数の呼び出しを意識してかんがえると、そりゃもう普通のことやってんじゃんあたりまえじゃんと思えます。
うんうん、でも、そもそも即時関数を使う必要があるんでしょうか。
定義と呼び出しがまとめて行えたらどういった効果(良いこと)があるのか?
即時関数は定義と呼び出しをまとめてできるってことはわかりました。
しかしながら、なんでそんなことする必要があるの?って疑問がわいてきます。先ほどの例でいえば、
function hoge() {
alert(1);
}
hoge(); // 1
この形でも良いじゃないかと。
「確かに即時関数だとまとめて書けて良いかもしれない。でも別に定義と呼び出しを分けてやってもいいじゃないか!普通に書けばいいんだ!わざわざ即時関数にして私ってできるだろ?すごいだろ?結婚する?的なアピールやめろよ!あと結婚するよ!パンパカパーン!」
と思ったかもしれない。
即時関数男さんと結婚出来美さん、ちょっと即時関数男さんは生意気で高飛車なところもあるけれど、なにをやるにしても早いのが素敵なの。というかもう後がないの結婚しましょ!印鑑!印鑑!結婚届けどこおおおおおおお!
という感じですか?
まあともかく。いやこれはごもっともな話で、ではなぜ即時関数を使うのかと言えば、「グローバル変数の使用を抑えることができるから」という理由ですね。
って最初にこの理由を聞いて「ほうほう!そういうことかほうほう!」と納得できれば世の中みんな幸せなのですが、「グローバル変数の使用を抑えることができる」って抽象的な言葉でなんのこっちゃよくわからん。
そこで具体的にどう抑えられるかってのが次。理由は大きく2つあります。
1. グローバル変数に関数の割り当てがなされない
1つ目の理由は、即時関数だとグローバル変数に関数の割り当てがなされないことです。具体的な意味は、まず必要とする前提知識の確認のコード。
var hoge = 'ほげー';
alert(hoge === window.hoge); // true
なぜtrueになるか理解できれば大丈夫。グローバル変数は実際にはグローバルオブジェクトのプロパティです。
ブラウザの場合グローバルオブジェクトはWindowオブジェクトですね。Windowオブジェクトはwindowって自己参照のプロパティがあるんでwindowという小文字を使います。
なので、hoge === window.hogeはtrueということに。
ここでWindowオブジェクトやプロパティといった単語が理解できないと辛い。適当な入門書であれば言及しているはずなので確認してみてください。
そいで、これは関数でも一緒です。
function hoge() { alert('ほげー'); }
alert(hoge === window.hoge); // true
先ほどの普通の変数の例と一緒。
変数だけではなく関数も変数と同じようにグローバル変数に割り当てられています。つまり、グローバルの空間で関数定義すれば関数もWindowオブジェクトのプロパティになります。
関数ってどこか特別な感じがして、変数と区別して考えてしまうかもしれません。しかし、JSではどちらも同じように管理します。varやfunctionで定義しても、グローバルで宣言された変数や関数はWindowオブジェクトに属します。
変数だからとか関数だからって別々に区別しません。なので、
function hoge() { alert('ほげー'); }
alert(hoge); // function hoge() { alert('ほげー'); }
var hoge = 'ふげー';
alert(hoge); // ふげー
window.hoge = 'へげー';
alert(hoge) // へげー
代入するごとに値が変わっているのが分かります。この結果が成り立つのは当然ですね。
ここまでを踏まえて本題。
即時関数を使えば「グローバル変数に関数の割り当てがなされない」とは、今までを理解していれば次のコードですぐわかります。
(function hoge() { alert('ほげー'); })();
alert(hoge) // ReferenceError: hoge is not defined
ReferenceError: hoge is not definedは、「参照エラー: hogeは定義されていません」という意味。つまり、「hogeという関数はどっこにもありませんなー」と言われています。
関数にhogeって名前が付いているので「この関数もhogeというグローバル変数に割り当てられてるのかなー、window.hogeみたいになっているのかなー、とりあえず結婚しようかなー」と思ったら大間違い。しくしく。
即時関数は定義と呼び出しをまとめて行っています。だから、グローバル変数に設定する前に関数に定義された処理は役目を終えて消えました。なのでどっこにもねーよボケとエラーで怒られたんです。ぐすん。(関数宣言ではなく式として評価されたので割り当てもクソもないのです)
せっかくわざわざ名前つけてやってんのに意味がない。こんな放蕩薄情野郎に名前を付けたってしょうがないじゃん。
ってなことで、
/* 名前つけずに無名関数にする */
(function() { alert('ほげー'); })();
よく見る無名の形になる。
小見出しの「グローバル変数に関数の割り当てがなされない」という意味は、つまり、即時関数であればグローバル変数に割り当てられることなく関数が呼びだすことができるということです。
これが即時関数がグローバル変数の使用を抑えることができる1つ目の理由。
さて、これ以外にもう1つ抑えることができる理由がありまして。即時関数はそもそも関数なのですからスコープが提供されます。
2. 即時"関数"だから関数内部の変数はローカルに限定される
2つ目の理由は、即時関数を使えば内部で宣言した変数や関数はローカルに限定される、というものです。
これは前提知識としてJSのスコープを理解していなければなりません。すでにグローバル変数など単語を出しているのにいまさらですが。
スコープとは変数(関数も含む)の有効範囲です。有効範囲と言うとむつかしいイメージがしますが、変数や関数を参照できる場所(利用できる場所)を限定する仕組みのことですね。(プログラミングでは「変数の参照」とか「変数へのアクセス」とかって表現することがありますが、要は変数を使うってことです)
そしてJSのスコープは基本的にグローバルスコープとローカルスコープという2つのスコープに分けられ、ローカルスコープは関数で提供されています。
専門用語ばっかりじゃあれなんで、とりあえずスコープを簡単にレッツ体験。
function hoge() {
var local = 'ローカル変数';
}
alert(local); // ReferenceError: local is not defined
関数の中で宣言したlocalという変数を、関数の外でalertしたらどっこにもないよーってエラーになりました。これは関数の中のlocalというローカルスコープを持つ変数が関数内に閉じ込められているためです。
このように関数内部で宣言された変数は関数の外部からは参照できません。(プログラミングではこのことを「変数がみえない」と言うことがある)
もちろん関数同士だって外部にあたりますので、
function hoge() {
var local = 'ローカル変数';
}
function fuga() {
alert(local); // ReferenceError: local is not defined
}
fuga();
localという名前の変数が無いじゃねえかゴルァーってエラーになります。なんで、関数内部で宣言された変数の有効範囲は、
function hoge() {
var local = 'ローカル変数';
alert(local) // ローカル変数
}
hoge();
その関数と同じ空間だけってことね。
関数外部の変数はグローバルスコープを持ち、その変数を総称してグローバル変数と言います。関数内部の変数はローカルスコープを持ち、総称してローカル変数と言います。
このようにJSで扱う変数は基本的に2つのスコープのうち、どちらかに属することとなります。
ここまでで専門用語に追いついていけなかった用にまとめておきますと、
<script type="text/javascript">
/* 関数の外で宣言された変数はグローバルスコープを持つ */
/* それらの変数を総称してグローバル変数と言う */
var global = 'だからこれはglobalという名前のグローバル変数だね';
function hoge() {
/* 関数の内で宣言された変数はその関数のローカルスコープを持つ */
/* 関数内部で宣言された変数を総称してローカル変数と言う */
var local = 'だからこれはhoge関数のlocalという名前のローカル変数だぬぇい';
}
</script>
scriptタグがあると分かりやすいかな。(面倒なんでこれ以外はscriptタグを省略してます)
そしてグローバル変数はプログラム全体から参照できますが、ローカル変数はその関数内部からしか参照できません。
グローバル変数の「プログラム全体」とは、
var global = 'グローバル変数';
function hoge() {
alert(global) // グローバル変数
}
hoge();
関数内部からでも呼び出せたりすることです。(ローカル変数の結果と混同しないように注意)
こんな感じで、ローカルだのなんだの関係なくどこからでも見えますよー参照できますよーってのがグローバル変数。
それに対してローカル変数は、もう分かりきっていることですが、
function hoge() {
var local = 'hogeのローカル変数';
alert(local) // hogeのローカル変数
}
/* 関数内部でalertすることはできるけど */
hoge();
/* 外部からだとどこにもないよーって怒られました */
alert(local) // ReferenceError: local is not defined
ローカル変数の有効範囲はその関数の内部だけです。
ここまでを前提に次から本題。
というかもう答えは最初から出てます。
関数内部で正しく宣言されたローカル変数は外部に漏れることがありません。それらはグローバル変数にはならないのです。
最初の例と同じコードですが、
function hoge() {
var local = 'ローカル変数';
}
alert(local); // ReferenceError: local is not defined
関数外部からローカル変数は見えません。これは即時関数の形にしても同じ。
(function() {
var local = 'ローカル変数';
})();
alert(local); // ReferenceError: local is not defined
カッコがついて別のものに見えるかもしれませんが、ただの関数ですから当然です。内部で宣言されたローカル変数は外部から参照できません。
もちろん内部で定義された関数も同じです。
(function() {
function local() {
alert('ローカル関数');
}
})();
alert(local); // ReferenceError: local is not defined
関数も外部からは見えません。(こういった関数の中の関数はローカル関数とか内部関数と称されています)
このように変数も関数も閉じ込められます。
そういうわけで、小見出しの「即時"関数"だから関数内部の変数はローカルに限定される」の意味は、つまり、関数内部で正しく宣言された変数や関数はローカルに限定されグローバルに影響を与えることがなく、関数内部に閉じ込められるということです。
関数内部で完結するので、グローバル変数を1つも作らずに処理を行なうことができちゃうわけですね。わーいわーい。
これが2つ目のグローバル変数の使用を抑えることができる理由でした。
なお、この項目ではスコープの説明は不十分です。いろいろ省きましたが、関数内部でのvar無しの動作や重要なスコープチェーンとそれの発展としてクロージャというものがあったりします。
大切なことなので知らない人は入門書やWebで検索したりして学習してください。
javascript ?X?R?[?v - Google ????
スコープという概念は簡単なんだけど、それを言葉で表現するとなるとむつかしいです。早い話がコード書けば自然に身につくものなので、理屈で攻めても理解できないならコードを書くしかありません。
即時関数がグローバル変数の使用を抑えることができる理由まとめ
長いこと続いたので、以上の2つの理由をまとめると、
即時関数を使えばその関数はグローバル変数に割り当てられない
関数内部で宣言した変数やら関数はローカルに限定されグローバルに漏れない
というわけで、一切グローバル変数を利用することなくコード書けて便利!最高!結婚しよう!イエー!マリッジブルゥー!!!ってことでした。
まとめると簡単に言えちゃうことだったりしますが。理解しているからこそ簡単と言えるのであります。たぶんそんな落とし所です。
グローバル変数の使用を抑える意味
補足として。なんでどいつもこいつもグローバル変数を使わないことにこだわっているのかというと。
それは変数の名前が衝突すると厄介だからなのです。たとえば、404 Blog Not
Found:javascript - ブログパーツ/ウィジェット開発者におねがいが良い例です。ちょっこしリンク先を見てください。
こちらでも簡単に流れを記述しておきましょう。js部分。
<script type="text/javascript"
src="http://blogchart.jp/js/blogparts.js"></script>
<script type="text/javascript">
<!--
id="22";
blogurl="http://blog.livedoor.jp/dankogai/";
partstype="b";
viewBlogparts();
// -->
</script>
最初のscriptタグはhttp://blogchart.jp/js/blogparts.jsのjsファイルを読み込んでます。読み込んだコードは下記の通り。
function viewBlogparts(){
var rs = Math.round(Math.random()*2147483647);
var link = "http://blogchart.jp/blog?url="+blogurl;
var imgsrc =
"http://blogchart.jp/blogparts?type="+partstype+"&id="+id+"&referer="+document.referrer+"&rs="+rs;
document.write("<a href='");
document.write(link);
document.write("' target='_blank' >");
document.write("<img src='");
document.write(imgsrc);
document.write("' border=0 width=163 height=53 />");
document.write("</a>");
}
この時点でviewBlogpartsというグローバルな関数が1つ割り当てられます。次にscriptタグの間にコードを書いている部分がありますね。
id="22";
blogurl="http://blog.livedoor.jp/dankogai/";
partstype="b";
viewBlogparts();
idとblogurlとpartstypeという変数は全てグローバル変数で値が代入されています。ブログパーツの設定を行なう値ですね。
設定値はブログパーツの外見やどのブログURLを対象とするのかといった設定でしょう。そしてこれらの変数はviewBlogpartsの内部で参照されていることが分かります。var linkとかvar imgsrcとかのとこです。
グローバル変数はプログラム全体から参照することができます。なのでviewBlogpartsという関数の内部からグローバル変数を参照することが可能です。
プログラムがどう動作しているのかまとめると、
グローバル変数に設定値を代入
viewBlogpartsの呼び出すわけですが、その時にグローバル変数を参照してlinkとimgsrcの値を生成
最後にdocument.writeでブログパーツを挿入している
という流れ。
これはやっちゃいけないですね。どこがいけないかというと、ブログパーツの設定値をグローバル変数で設定している部分です。
例えば他に読み込むjsファイルのプログラムでもグローバル変数を使っていて、その名前がidだのblogurlだのとviewBlogpartsで利用する変数とかぶっていたら値が書き換わってしまいますね。
すると予期せぬ動作を引き起こすかもしれません。というか、現に404 Blog Not
Found:javascript - ブログパーツ/ウィジェット開発者におねがいの画像のような結果を招いています。
あとグローバル変数ばかり使ってると可読性がスパゲティ(コードがめちゃくちゃな感じ)になるから使うのやめようって意図もありしますが、それはまた別の話。
ちなみに、今回の問題の解決策は設定値は引数で渡すようにしたらどうかと提案してくれています。これだと、
function viewBlogparts(obj){
var id = obj.id || 1,
blogurl = obj.blogurl || 'http://blogchart.jp',
partstype ~ obj.partstype || 'a';
var rs = Math.round(Math.random()*2147483647);
var link = "http://blogchart.jp/blog?url="+blogurl;
var imgsrc =
"http://blogchart.jp/blogparts?type="+partstype+"&id="+id+"&referer="+document.referrer+"&rs="+rs;
document.write("<a href='");
document.write(link);
document.write("' target='_blank' >");
document.write("<img src='");
document.write(imgsrc);
document.write("' border=0 width=163 height=53 />");
document.write("</a>");
}
/* 使うとき */
viewBlogparts({'id': 22, 'blogurl': 'http://blog.livedoor.jp/dankogai/',
'partstype: 'b'})
オーソドックスな形ですがこうすれば引数で渡せます。これでありきたりな変数名のグローバル変数を使う必要がなくなりました。(が、こういうのはiframeでやっちゃうべきですね。たぶんね)
この事例では即時関数は必要ありませんでしたが、使って対処する方法もありますし、オブジェクト1つ用意してなんやかんやすることもありますし、手段はいろいろあります。
なんでもいいので一番しっくりくる方法がいいと思います。
なぜ即時関数はカッコ厨なのか
ここまでは、即時関数は「どういったことができるのか」ということと、「どういった効果があるのか」についてかんがえてきました。
これらの答えは、
関数定義と関数の呼び出しをまとめて行なうことができる
ということができて、
グローバル変数の使用を抑えることができる
といった効果がある、ってことでした。
これだけ理解できれば扱う分には問題ないでしょう。
でも、「即時関数はなぜカッコ厨なのか!」という疑問が魂の叫びとしてふつふつと湧いてきてますね。きてますね!
つまり、(function(){...})()の形で即実行する理屈がわからん!とか、functionの前に" ( "があったり後ろで" )( ) "があったりして何なの!?結婚するの!?とか。
見た目で惑わされていないでしょうか。いや、惑わされているよきっと。あなたは、惑わされている!
なぜならば、この蠱惑的な姿形をもった即時関数はJS界におけるレディー・ガガ。最初に出会ったときから惑わされる(理由もなくどん引きする)様は同じなのです。
それでも、この世は実に素晴らしく、誰もが即時関数の惑わしから解き放れていないわけではありません。俗物から解脱した聖人もいらっしゃるのでございます。なのでWebで検索すればたいていどなたかがなんでカッコ厨か言及しております。
聖人バンザイ、ブッタバンザイでございます。般若心経を唱えたい一心を抑えて、聖人様方の言い分をまとめますと、
関数を式として評価させるため
だからカッコ厨なのです。
これが解脱への第一歩ですね!さあ、解脱したらブッタの髪のボツボツをほどく作業に戻るんだ!バリカンで一度に剃ろうとすると固すぎて刃が折れちゃうからね!そのためにも関数が式だかなんだかをさっさと学習しなくっちゃね!
ところで式ってなんでしょう?
関数には、というかJSには式(Expression)と文(Statement)が存在する
関数というかプログラミング言語には(他の言語はいざしらす少なくともJSには)式と、それから文というものが存在します。
文といえばただの文章を思い浮かべたり、式というと数学で使う数式が思い浮かぶかもしれませんが、それだけのイメージだとだめです。具体的にどうだめなのかというと私と一緒です。
・・・ね、だめでしょ(´;ω;`)
少し話が膨らんで長くなりますが大事な概念なので式と文についてみていきましょう。
式(Expression)と文(Statement)って何だろう?
プログラムを構成する要素は式と文に分類できまして。JSにおける式と文は次の通り。
式
11 式 (Expressions)
文
12 文 (Statements)
リンク先は意味わからんかも。最初のうちはわからないものです。慣れてくるとね、うん、やっぱりわからなかったりします/(^o^)\
もうちょっと具体的にわかるよう例を交えて示します。
式とは何だろう
式とは何かと言われて何を思い浮かべるでしょうか。
もしかしたら、
100 + 200 = 300
みたいな式を思い浮かべたかもしれません。これはいわゆる数式の類ですね。
このように「式=数式」といったようなイメージしか持っていなかった人。
大丈夫。そんな人たくさんいる。私とか、私とか、私とか、あと私とか私とか。私が10人くらいいるから。ある意味やばいけど安心!マイノリティじゃないよ!!大丈夫!NARUTO読んで勉強したし、スラムダンクでフンフンディフェンスのコツ考えてたし!
そいでJSにおける式とは、上記のような数式も含めて、
値を持つもの
のことを意味します。
具体的に例を挙げると、
'あいうえお' // 文字列
100 // 数値
true // 真偽値
null
[1,2,3]
{a:1, b:2}
count // 変数の参照
これらは式です。
「え?そ、それ式?まじで?ま、まじで式なの?「100」ってあるだけで式になるの?え?数値だけで式?文字も式?ええ?それになに?変数名がぽつんとあるだけでもし、しぃきなのおおおおおおお!?えええええ!?とりあえず結婚するううううう!?」
って発狂してもおかしくない。と、経験者は語る。(はふー)
数式だけを式として認識しているとあかんのです。
それから、値を変数に代入するのも式です。
x = 100
y = 'あいうえお'
= みたいな記号があるから式だろうとまだ思えるかな。このように代入は式として扱います。(後述しますが、varをつけたりセミコロンつけたら文になります)
また、
100 + 100
'あいうえお' + 'かきくけこ'
50 < 100
'あいうえお' === 'あいうえお'
これらも式です。なんとなく式と言われたらそうだろうと思えますが。演算子あると式っぽい感じします。
「100」や「'あいうえお'」のように = や + や - などの演算子が無いただの数値や文字列も、「x = 100」や「100 + 100」といったものも全て「値をもっている」ので式で
す。
なんでこういったものが式なのかというと、そのように定義されているからです。それ以外に言葉がないですね・・・。うーん。たぶんこの概念はプログラミングだけじゃないと思うのですが・・・。
やっぱりわかりにくいですね。そういうわけでわかりやすいように考え方を変えましょう。「式とは値を持つもの」と言いましたが、言い換えると「式とは値を返すもの」とも言えます。
でも値を返すって具体的にどういうことなのでしょうか。これはChromeのコンソールやFirefoxのWebコンソールで試すとわかりやすい。
たとえば、100と入力して実行すると、
f:id:sandai:20110817162152p:image
といったように100と「返ってくる」でしょう。( > xxx の部分が入力した文字で、その下が返ってきた値)
他には、
f:id:sandai:20110817162153p:image
文字列の値が返ってきました。
見た目が式っぽいやつも、
f:id:sandai:20110817162154p:image
それぞれ値が返ってきています。
x = 100 も式だと例に挙げていましたが、
f:id:sandai:20110817162155p:image
こうして値を実際に返すからです。ちょっとよくわからないかもしれませんが、式全体は値を持っているのです。
そして、
f:id:sandai:20110817162156p:image
といったように x = y = 100みたいな記述が可能なのは代入が式だからですね。
このように式とは数値、文字列、オブジェクト、変数などそれぞれ1つ1つを表し、
100
さらに、それらは演算子によって代入や加算や比較などさらに「複雑な式」(これも値を持つもの、返すものの意味での式です)を構成し、
x = 100 + 300
また、これらは値を返すという特徴を持っていて、
f:id:sandai:20110818200924p:image
式とは値が返すもの、あるいは、値を持つものとまとめて言うことができます。
こういうわけですが、やっぱり難しいかもしれません。最初はこうして式とは値を持つものといわれてもなんのこっちゃ分からんと頭をかかえるものです。
そのような場合は、
x = 変数に格納できるやつだいたい式っす
と思っていれば簡単。あるいは、
/* xに入れることができるのだいたい式っす */
if(x) {}
でも。ifの方が正確かな。式というのは結局値です。変数に格納したり条件式に使えますからね。
文とは何だろう
分類すると大きく4つに分けられます。(わかりやすいよう非公式に分けてるだけ)
1. 式の後ろにセミコロンがついたら文
2. 空文
3. varをつけた代入文
4. ブロック文, if...else 文, switch 文, for 文, do...while 文, while 文,
label 文, break 文, continue 文, for...in 文, for each...in 文, with 文, コメント, throw 文, try...catch 文など
参考:Statements - JavaScript | MDN
覚えなくてもいいので式との違いをつかんでください。
1. 式の後ろにセミコロンがついたら文
式のケツにセミコロンがつくと文となります。
/* 式 */
x = '式'
100
'あいうえお'
100 > 50
/* 文 */
x = '文';
100;
'あいうえお';
100 > 50;
セミコロンが無ければ式ですが、あれば文となります。なんか変な話ですけどそういうものなのと決められているので、そういうものだとしか言いようがありません。
納得したいのであれば、根本的な理由ではありませんが、
if(1 + 1;); // syntax error
これならなんとなく納得できますよね。条件は式しか記述できませんのでエラーです。
このような文を厳密には式文と言います。
上の例は全て文法上認められた文であるというだけの無意味な文です。代入の例はともかく、実際にプログラム中にこういった記述をすることはありません。たんなる例です。
JSでは制御文や関数宣言を除けばだいたいこの式文の集まりですが、" { "とfunctionキーワードが文の頭にある場合は式文として解釈されません。なぜなのかというと、それは書いてあります。
Block と曖昧になることから、 ExpressionStatement は大括弧 "{" で開始することはできないことに注意。また、 FunctionDeclaration と曖昧になることから、
ExpressionStatement は function キーワードで開始することもできない。
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/12_Statements.html#ExpressionStatement
つまり、" { "はブロック文(ifやforや関数定義で使う { } のこと)と、functionキーワードは関数定義とかぶるのでそれらが文の最初にあるときは式文としないよーということです。
2. 空文
セミコロンだけでも文です。独り立ちしてます。一本足で立ってて立派です(´;ω;`)ブワ
;
この文は厳密には空文と言います。これが文かよとちょっとビックリしちゃいますが文です。
空文は何も行わないことを「行なう」文です。変な日本語ですが、文の定義上そう表現するのが適しているかなと。まあ結局何もしないってだけです。
文法として覚えていなくたって支障はありません。あとC系の流れを組む言語にはだいたい空文があるんでJSに限った文ではないようです。
3. varをつけた代入文
代入のうち、
x = '式'
y = '文';
といったようにセミコロンある無しで式と文に分けられましたが、varをつければいずれも代入文となります。
var x = 'これは文'
var y= 'これも文';
正しくはvar文(変数文)と言います。セミコロンが無い場合でもvar文は自動でセミコロンが挿入されることになります。(式文でも挿入されますね)
あと、これまでvar無しで代入のコードを使ってきましたが通常はvarつけます。つまり変数宣言(この場合宣言とはvarをさす)していないのに代入することはまずないということです。
var x = 'varをつかって代入しているのでおっけーです;
var y;
y = 'varで宣言されている名前への代入なので、varがこの行に無くてもおっけーです';
z = '単なる代入はまずしません';
どこでもよく言われていることなので蛇足かもしれませんが念のため注意書きしておきます。
4. ifやforなどその他愉快な仲間たちの制御文
ブロック文, if...else 文, switch 文, for 文, do...while 文, while 文, label
文, break 文, continue 文, for...in 文, for each...in 文, with 文, コメント,
throw 文, try...catch 文などは文です。
Mozillaさんでまとめてあるので、
Statements - JavaScript | MDN
をご覧ください。この他にも制御文は存在しますが主旨と関係ないので特に言及しません。
以上がJSにおける文ですが、文とは何かと一言ではなんのこっちゃ表せなかったりします。
困ったので本でも確認したのですが、「副作用が伴うもの」とか「JavaScriptに何かさせるもの」が文だそうです。抽象的すぎて伝わりにくい。
またまた困ったので、wikiで調べたら、
プログラムにおける文(ぶん、statement)とは、コードの記述単位の1つ。1つの文が1つの手続きを表すことが多い。
.
.
.
大まかに言えば、一つ以上の式や関数呼び出しで作られる、手続き構造の分割できない基本単位が文である、と考えてほぼ差し支えない。
http://ja.wikipedia.org/wiki/%E6%96%87_%28%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%29
といったことだそうです。いくぶん分かりやすいかもいれない。
そんなわけで本も含めて得た情報をまとめると、
文とはJavaScriptの実行における基本単位で1つ以上の式や関数呼び出しなどからなるもの
と、言えますが。んー、分かりやすく表現できなくて申し訳ない。言葉にするとなるとちょっと難しいです。
とりあえず、式と文の言葉の区別がつけば問題ありません。式文だの空文だのといったのはこれから出てくる用語の説明ためですので、無理に覚えたりしなくても大丈夫です。
個人的にはJSにおける文と式の境界線はさほど明確ではないように思える(実際には式文は式の値を返すし、ブラウザだと文でもundefinedを返すし)ので、ここまではっきり区別することもなかったかなというところですが・・・。
難しい。どう言い切ってよいものやら。とりあえず着地はしたので文は終わり。話膨らみすぎたかな(;´∀`)
ここまでの式と文のまとめ
長くなったのでおさらい!
えーと、即時関数がなぜカッコ厨なのかといえば関数を式として評価するためでした。ほいで式ってなんだよという話になり、JSにおける式と、それから文の概念を学びました。
式とは値を持ち文や式の一部を構成するもの
文とはJavaScriptの実行における基本単位で1つ以上の式や関数呼び出しなどからなるもの
まとめるとこんな感じです。
以上のことを頭において即時関数のカッコ厨の理由と、それに関連する関数の式と文について話を進めていきます。式と文の意味が分かっていれば簡単です。
あと、これまで式と文のうち関数は一切例として挙げていませんでした。というのも、関数には式と文の2種類あるからです。それらの見た目は全く一緒なので、見分けがしづらいというか、微妙なのです。
ぶっちゃけ面倒だったのでまとめて書きたかったという個人的な都合です。そんなわけで、次で即時関数のカッコ厨と関数の式と文ともろもろまとめて終わり。
なぜ即時関数はカッコ厨なのかリターンズ
同じ見出しが上の方にあるんでリターンズで。
関数には式と文の2種類あります。そのうち、関数定義と呼び出しをまとめて行うようにするには関数を式として評価させなければなりません。なぜなら文のままだとエラーになっちゃうからです。
まずはこれがどういうことなのか確認。
関数宣言で即時関数のような動作ができないわけ
関数の文とは関数宣言のことです。
function hoge() {
alert('関数宣言です。関数の文という位置づけのものです');
}
即時関数は関数定義と呼び出しをまとめて行なうものですよね。関数宣言でもそうしたいのであれば、ケツに関数呼び出しの演算子である( )をつける形になります。
そうしてつけてみると、
function hoge() {
alert(1);
}(); // syntax error
あひー!!エラーになっちゃった!syntax errorとは構文エラー。つまり「決められた通りに式と文が書かれていないよー」といった意味です。
なぜエラーになったかというと、JSでは、
function hoge() {
alert(1);
}
();
このように改行が入っているみたいな解釈がなされているんですね。( )は関数呼び出しを行なう演算子ですが、文の先頭なので呼び出しもクソもないわけです。だから文法エラーになっちゃったのです。
でもなんで改行が入ったように解釈されたのでしょうか?井手らっきょのせいでしょうか?
うーん、それは否めないけれども、いやむしろそうであったら「裸になること禁止令」を出せば良いだけれども、これは( )だったからこうなったとか特別な動作ではなく、たとえばセミ
コロンでも同じ結果になります。
function hoge() {
alert(1);
}; // セミコロン
/* どう解釈されるかというと↓ */
function hoge() {
alert(1);
}
; // セミコロン
空文になっちゃいました。このように、関数宣言における終端の波括弧(" } ")で文は終わりとなっていまして。正確に言えば関数宣言そのもので文は完結しているのです。
んーと、これは波括弧だからいまいちイメージが沸かないかもしれませんが、改行が入る現象を別の文で表すと、
/* 関数ではありませんが、上記の改行が入る形になる現象は、 */
/* 結局こういうことになってるのと同じ */
var x = 1; + 2;
/* これがどう解釈されるかというと↓ */
var x = 1;
+ 2;
当たり前ですがセミコロンの後に続けて式が書けるわけがありません。
関数宣言に( )をつけて書くというのは、これほど無意味なことをやってるに等しく、文の後ろで式が(正確には文が)書かれていることと一緒です。(上記のコードは関数宣言における終端の波括弧とセミコロンが同じという主張ではなく、「文の終わり」という点だけが共通していることを示した例です)
なので、同じように( )でもセミコロンでも関数宣言とは別の文として解釈されたのです。なんとなくイメージが湧いたでしょうか。
こうして関数宣言ではできないため関数を式として評価させることで即時関数の動作を実現するに至り、めでたく井手らっきょはダグトリオに進化しました。目新しい!やったね!ドッゲドッゲブリュリュイイイイイ!!!
終わり。
じゃなあああくて。
関数宣言だと即時関数のような動作を実現することはできないとわかりました。だから、関数を式として評価させることで( )をケツにひっつけて呼び出せるようにするのです。
では具体的にどうであれば関数は式となり、あるいは、文となるのでしょうか。
関数における式と文の関係
その関数が式なのか文なのかが決まるのは、functionという文字が行の先頭にあるかどうかという点です。行の先頭にあればそれは関数宣言(関数の文)となり、それ以外であれば関数は式となります。
なぜそう言えるのかというと、はっきり書かれていませんが式文の項でこのように書かれています。
...また、 FunctionDeclaration と曖昧になることから、 ExpressionStatement は
function キーワードで開始することもできない。
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/12_Statements.html#ExpressionStatement
「functionキーワードが行の先頭にあると関数宣言とかぶるので式文としない」とあります。
つまり関数定義のうち「functionキーワードが行の先頭にあるならば関数宣言である」と言えますね。これを言い換えると関数定義のうち「関数宣言でないのであればfunctionキーワードは行の先頭ではない」とされ、関数は文と式の2種類しかありませんので、行の先頭にfunctionがなければそれは関数宣言ではなく式であると導けます。
そういうわけで、functionが行の先頭にあるなら関数宣言となり、
function hoge() {
alert('functionが行の先頭にあるので関数は文です');
function piyo() {
alert('関数の中の関数でも、行の先頭にあるので関数は文です');
}
}
function fuga() { alert('インデントがなくても行の先頭にあるので関数は文です');
}
それ以外なら関数は式であると言えます。
var hogera = function() {
alert('functionの前に = や var があるので関数は式です');
};
[
function() {
alert('配列に格納されてるときもfunctionより先に [ があるので式です');
}
];
if(function() {alert(1); }){
alert('こんな不細工なことやりませんが式なので条件式にも使えます');
}
(function() {
alert('(1+ 1)と同じ意味での( )で関数をくくれば、functionより先に ( があるので式となります');
});
雑な言い方になりますが、functionより前に何か文字がなければ関数宣言ですし、なんかあれば関数は式になるって感じです。
それから関数宣言で関数名は必要ですが関数の式では省略できます。(関数の式で名前をつけるとしたら何か目的を持ってつけます。特に付ける理由がないのであれば無名で問題ありません)
このようにその関数が式なのか文なのかといったことは単純な仕組みだったりしますが、慣れないうちは混乱することがあるかもしれません。しかしほぼ文法上の違いですから、関数は式でも文でも機能は変わらないと意識しておけば問題ないです。
即時関数の仕組み
ここまでで関数を式として評価させる理由と、その方法を確認してきました。
式として評価させる理由は、
関数宣言のままだと関数呼び出し演算子の( )を使うことができないから
で、関数を式として評価させる方法は、
functionキーワードを行の先頭におかない
というものでした。
こういったことが理解できれば、カッコなばけものに見えた即時関数もどういった仕組みで成り立っているのかみえてこないでしょうか。
まず関数を式とするために (1 + 1) といったように利用するグループ化演算子の( )で関数をくくります。
(function() {
alert('関数を( )で囲んでいます。この時点で関数は式となっています');
})
functionより前に ( があるので式となりますね。そうして、関数呼び出しの演算子 )を最後にくっつけることで、
(function() {
alert('関数呼び出しの演算子である( )をくっつける');
})(); // ←関数呼び出しの( )ね
関数定義と関数呼び出しをまとめて行なうことができる即時関数ができました。
(1 + 1)といったように使うグループ化演算子の( )と、hoge()といったように使う関数呼び出し演算子の( )の区別がついていないと、単なるカッコ厨に見えてしまいますが区別で
きればわかりやすいですね。
さて、関数を式として評価させるために即時関数ではグループ化演算子の( )を使って関数全体をくくっています。でもよく考えたらこれって別に( )でくくらなくてもいいですよね。
関数を式とするにはfunctionキーワードを行の先頭におかなければ良いので、その他にも方法はあるわけです。
たとえば、
+function() {
alert('これでも即時関数です。実はカッコである必要はないのです');
}();
こうしても問題ありません。functionの前に + があるので見た感じだとエラーになりそうですが、関数は正常に呼び出すことができます。その他同じような例としては、即時関数(function(){ ... })()の別の書き方いろいろ -
泥のようににいくつか紹介されているのでどうぞ。
このように必ずしも即時関数はカッコ厨である必要はありません。カッコで関数をくくることは式として評価させるための、いくつかある方法のうちの1つにすぎないのです。
とはいえ一般的に使われているのはカッコでくくる方法なのでその習慣に習う方が良いでしょう。
なぜ即時関数はカッコ厨なのかまとめ
即時関数はなぜカッコ厨なのかいえばそれは関数を式として評価させるためでした。
即時関数は関数定義のあとにすぐ呼び出すコードです。関数宣言のまま関数呼び出しの演算子で呼びだそうとすると、それらは別々の文として解釈されてしまうためエラーになります。
function hoge() {
alert('関数宣言');
}
(); // syntax error!!!
そこで定義の後にすぐ呼び出しができるよう関数を式として評価させてます。そして、その方法はカッコで関数をくくるというものでした。
(function hoge() {
alert('即時関数どす');
})();
これが一般的に即時関数と称されるコードです。
ですが、関数を式として評価させる方法はカッコでくくる以外にも方法があり、
+function() {
alert('これでも即時関数');
}();
このような書き方でも即時関数として利用することができるのです。
関数をカッコでくくるのはいくつかある方法のうちの1つにすぎません。ただし、一般的に使われているのはカッコでくくる方法なのでその習慣に習って利用した方が良いと言えるでしょう。
といったところで終わり。
ポイントは式と演算子と文ですね。これらが何となくでもわかれば文法上の悩みは消えるでしょう。黒魔術的なコードについては、えー黒魔術師を目指すのであればがんばってください。JSは黒魔術が結構あるので楽しいかもしれません。私は拒絶反応がでるので止しときます。たまねぎ剣士でいいんです。
ここまででかなりくどく書いてきましたが、なるべくコードではなく言葉で表現したつもりです。こうすると冗長になってしまってだいたいは読むのをやめるもんですが、ここまで読んでくれたあなたは優しい。
よし、井手らっきょ2号の称号をあげます。ええ、ええ、わかっています。そんな感謝だなんてあははは。同じ井手らっきょ仲間じゃないですかあ。あははははあ。
・・・というわけで、まあ、マイノリティに悩んでいる人のお役に立てれば幸いです。
厳密には関数宣言は文ではない
今までの流れをぶったぎるような内容だけれど、実際のところFunction Statementという語句はありません。
JSだとどうなのかなと検索してみると、2つほど見たことあるサイト名があがってきまして。MDCやmsdnですね。どうやらstatementとして扱っているようです。
Statements and declarations - JavaScript | MDN
JavaScript Statements
JSでは文として扱っても問題ないということなのでしょう。というか文なのかな?静的な関数にそれはどうなのかとも思いましたが、文として広まっているし理解しやすい方がいいのでこの記事でも文としておきました。
関数定義の名前
定義については以下のページを参考。
関数と関数スコープ - JavaScript | MDN
機能としては全て関数を定義するって部分は一緒なのですが、それぞれ姿形が違ったり効果も微妙に違いがあるのです。
関数宣言
よく見かける普通の関数の構文。関数宣言と言います。
function hoge() {
//
}
ケツにセミコロンはいりませんので。関数式と比べるとパフォーマンスは良いみたい。特別な理由がない限りこの書き方が基本。
関数宣言の特徴として巻き上げが挙げられます。
alert(hoge); // function hoge() { return 1; }
var hoge = 1;
function hoge() {
return 1;
}
alert(hoge); // 1
定義のタイミングが関数宣言で次が変数って流れ。
関数式
関数リテラルとも言われます。あとMDCではfunction演算子とかも言われてますが。んー、function operatorは良い表現とは思えませんので私は非推奨です。リテラルもなん
か伝わりにくい。というわけで関数式おすすめ。
変数に関数を代入する構文です。JSらしい書き方ですね。
var hoge = function() {
//
};
無名関数でないケースもあります。「名前付き関数式」って言われていたりしますが、名前があろうが無かろうが関数式と抽象的に表現したりもするんで、ゆるゆるです。
var hoge = function fuga() {...};
この場合fugaはこの関数の内部からしか利用できません。だから通常は、
var hoge = function fuga() {
//
};
fuga() // error
となってしまうわけです。が、これJScriptでは漏れます。
Function Expression Statements: Days on the Moon
あとね、セミコロンは必須です。無いと、たとえばだけど、
var hoge = function() {
alert('セミコロンどこいったーヽ(`Д´)ノ');
}
(1 + 1) * 2 ;
としたら関数が呼び出されます。こんなコード後ろに書かないけど、もしなんか書くことあったらふわっとつけときましょう。というか常につけます。。
これらは関数式というかそもそもはvar文なのですが、なんでもかんでもvar文つってたら分かりにくいので特徴を表している関数式の名前で良いと思います。
Functionコンストラクタ
これは関数定義というわけではありませんが、関数を生成します。明確な目的がない限りまず使いません。
var x = new Function('y', 'z', 'alert(y + z)');
x(5,3);
知らなくても大丈夫です。
メソッド
JSではオブジェクトのプロパティが関数のときメソッドと称します。
var hoge = {
piyo: 123, // プロパティ
fuga: 'あいうえお' // プロパティ
hogera: [1,2,3]; // プロパティ
hogehoge: function() {...} // メソッド
};
メソッドであっても実際はプロパティですとか言うとややこしくなるけど、まあそんなややこしさの爆弾をJSは抱えています。プログラミング言語ってここまで定義が曖昧というか整理されていないものなんでしょうか。
(function(){}())と(function(){})()について
かの有名なダグラス・クロックフォードさんは、
(function() {
//
}());
ってつかえよーうって推奨してます。Lispの面影を感じる今日この頃。たぶん意図はあると思うんです。
でも見辛い。従来に慣れたんだ。嫌だ。やめてくれ。ダグラスさん、まだあっしは、あっしはこの既成概念から逃れることのできねえ俗物なんでごぜえますだ。
といったように身も蓋もない思いでこざいます。
申し訳ないのですが、これからさきどちらが広まるか知りませんけれども、今回は従来の形式を利用させていただきました。皆様はぜひともこの俗物のごとく嘆かわしい人物とならぬよう身を清め生きることをお薦め致します。
くそったれ長い!
大丈夫だ!長いと思うから長く見えるんだ!長くないと思ったら・・・・・やっぱり長い!神様に誓って長い!でも良いんだ!そんなことより暑いからアイス食べよう!おいしい!ありがとう!アイスの神様!というか最近涼しい!たぶんきっとエアーマンのおかげだと思う!ロックマンありがとう!
参考
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/
http://people.mozilla.org/~jorendorff/es5.html
http://d.hatena.ne.jp/yone-ken/20090421/p1
http://nanto.asablo.jp/blog/2008/01/21/2571626
https://developer.mozilla.org/ja/JavaScript/Guide
http://ja.wikipedia.org/wiki/%E6%96%87_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)
http://www.amazon.co.jp/dp/4873113296/
2014年12月31日水曜日
2014年12月26日金曜日
Pythonのデコレータを理解するための12Step
http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
Step1. 関数
>>> def foo():
... return 1
...
>>> foo()
1
これは基本ですね. Pythonにおいて関数はdefキーワードにより関数名とパラメータのリスト(任意)とともに定義できます.また括弧付きで名前を指定することで実行できます.
Step2. スコープ
Pythonでは関数を作ると新しいスコープが作られます.言い方を変えるとそれぞれの関数がそれぞれに名前空間を持つということです.
Pythonではこれらを確認することのできる組み込み関数も用意されていて, locals()で自身の持つローカルな名前空間の値を辞書形式で返却します.
>>> def foo(arg):
... x = 10
... print locals()
...
>>> foo(20)
{'x': 10, 'arg': 20}
またグローバルな名前空間についてはglobals()で同様に確認ができます.
>>> y = 30
>>> globals()
{..., 'y': 30} #Pythonが自動的に作るグローバル変数が他にも表示されるが省略
Step3. 変数の解決規則
Pythonにおける変数の解決ルールは
作成の際には常に新しい変数がその名前空間の中に作られる
参照は同じ名前空間内を検索し, 無ければ外側に検索を広げていく
というものです.関数のローカルスコープでグローバルスコープの変数を参照してみましょう.
>>> text = "I am global!"
>>> def foo():
... print text #1
...
>>> foo()
I am global!
関数の外側で定義したtextの内容がきちんと表示されていますね.#1ではまず関数内のローカル変数を探し, 無いので同じtextという名前のグローバル変数を探しにいっています.
では今度は, 関数の外側で定義した変数を, 関数内で変更してみましょう.
>>> text = "I am global!"
>>> def foo():
... text = "I am local!" #2
... print locals()
...
>>> foo()
{'text': 'I am local!'}
>>> text
'I am global!'
foo()が呼ばれた時にはtextの内容として関数内で代入した値がセットされていますが, 外側のグローバル変数のtextの値は変わっていません. #2では実際のところグローバル変数を探しに行かず, 関数foo内に新しいローカル変数textが作られているのです.
つまり関数の内側ではグローバル変数は参照はできるものの代入はできない, ということになります。
Step4. 変数のライフタイム
スコープだけでなくライフタイムについても知っておく必要があります.
>>> def foo():
... x = 1
...
>>> foo()
>>> print x #1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
ここでエラーが起こっているのは, 上述のスコープの問題だけではありません. 名前空間は関数fooが呼ばれる都度作られ, 処理が終わると無くなってしまいます.つまり上の例では#1のタイミングでは文字通りxという変数はどこにも存在していない, ということです.
Step5. 関数の引数とパラメータ
Pythonでは関数に引数を与えることができます. 定義時のパラメータの名前が, ローカル変数の名前として使われます.
>>> def foo(x):
... print locals()
>>> foo(1)
{'x': 1} # パラメータxがローカル変数名として使われている
Pythonでは関数にパラメータを設定したり, 呼び出し時に引数を与える様々な方法が提供されています. パラメータには必須パラメータと任意となるデフォルトパラメータがあります.
>>> def foo(x, y=0): # 1
... return x - y
>>> foo(3, 1) # 2
2
>>> foo(3) # 3
3
>>> foo() # 4
Traceback (most recent call last):
...
TypeError: foo() takes at least 1 argument (0 given)
>>> foo(y=1, x=3) # 5
2
#1の例ではxがパラメータ, デフォルトの値を指定しているyがデフォルトパラメータになります.#2が通常の関数使用例ですが, #3のようにデフォルトパラメータについては省略することも可能です. 省略された引数はデフォルトの値(この場合0)を取ります.
またPythonについては名前付き引数も使えるので, 名前を指定することで順番を気にせず引数を指定することもできます(#4). Pythonにおける引数はただの辞書だと理解していれば納得のいく動きです.
Step6. 関数のネスト
Pythonでは関数内にネストして関数を定義できます.
>>> def outer():
... x = 1
... def inner():
... print x # 1
... inner() # 2
...
>>> outer()
1
ルールはこれまで見てきたものと同じです. つまり#1ではローカル変数xを探すが見つからないので外側の名前空間を探し, outer内で定義されあているxを参照します.また#2ではinner()を呼び出していますが, ここで大切なのは innerというのも変数名の1つにすぎず, 解決規則に基づきouter内の名前空間内の定義を探して呼び出されている ということです.
Step7. 関数はPythonにおいてファーストクラスオブジェクトである
Pythonでは関数自身もまたオブジェクトにすぎません.
>>> issubclass(int, object) # Python内の全てのオブジェクトは同じ共通のクラスを継承して作られている
True
>>> def foo():
... pass
>>> foo.__class__
<type 'function'>
>>> issubclass(foo.__class__, object)
True
これが何を意味するかというと, 関数を一般的な他の変数と何らかわりなく扱える - つまり他の関数の引数として与えたり, 関数の戻り値として使うことができるということです.
>>> def add(x, y):
... return x + y
>>> def sub(x, y):
... return x - y
>>> def apply(func, x, y):
... return func(x, y)
>>> apply(add, 2, 1)
3
>>> apply(sub, 2, 1)
1
上の例では関数applyはパラメータとして指定された関数の実行結果を戻り値とするようになっていて, 関数add, subが引数として(他の変数と何ら変わりなく)与えられているのがわかります.
次の例はどうでしょうか.
>>> def outer():
... def inner():
... print "Inside inner"
... return inner # 1
...
>>> foo = outer() #2
>>> foo
<function inner at 0x...>
>>> foo()
Inside inner
上のapplyの例と異なるのは, #1で戻り値として実行結果ではなく関数そのものを指定しているということです.(inner()ではなくinnerを与えている)
これは#2のように普通に代入可能で, fooに関数が入っていて実行することもできることがわかります.
Step.8 クロージャ
上の例を少しだけ変えて見てみましょう.
>>> def outer():
... x = 1
... def inner():
... print x
... return inner
>>> foo = outer()
>>> foo.func_closure
(<cell at 0x...: int object at 0x...>,)
innerはouterによって返される関数で, fooに格納され, foo()により実行可能です...本当に?
Pythonの変数解決規則には完璧に従っていますが, ライフサイクルはどうなっていますか?変数xはouter関数が実行されている間のみ存在しています. ここではouter関数の処理が終わった後にinner関数がfooに代入されているので, foo()は実行できないのではないですか?
…この予想に反して, foo()は実行可能です。PythonがFunction clojures(クロージャ)の機能を持っているからで, これは グローバルスコープ以外で定義された関数(この場合inner)が, 「定義時」の自分を囲むスコープの情報を記憶している というものです. 実際に記憶されている事が上のようにfunc_closureプロパティを呼び出すことで確認できます.
「定義時」と書いたことを思い出してください. inner関数はouter関数が呼び出されるたびに新しく定義されています.
>>> def outer(x):
... def inner():
... print x
... return inner
>>> print1 = outer(1)
>>> print2 = outer(2)
>>> print1()
1
>>> print2()
2
上の例ではprint1やprint2に直接値を引数として入れなくても, それぞれの内部のinner関数が何の値を出力すべきかを記憶しているのです. これを利用して固定の引数を取るようカスタマイズした関数を生成することもできるということですね.
Step.9 デコレータ
いよいよデコレータの話に入ります.
ここまでの話を踏まえて先に結論から言うと, デコレータとは「関数を引数に取り, 引き換えに新たな関数を返すcallable(*)」です.
>>> def outer(some_func):
... def inner():
... print "before some_func"
... ret = some_func() #1
... return ret + 1
... return inner
>>> def foo():
... return 1
>>> decorated = outer(foo) #2
>>> decorated()
before some_func
2
1つ1つ理解していきましょう.
ここでパラメータとしてsome_funcを取るouterという関数を定義しています. そしてouterの中でさらにinnerという内部関数を定義しています.
innerは文字列をprintした後, #1で返却する値を取得しています. some_funcはouterが呼び出されるごとに異なる値を取りえますが, ここではそれが何であれとりあえず実行(call)し, その実行結果に1を加えた値を返却します.
最後にouter関数はinner関数そのものを返却します.
#2ではsome_funcとしてfooを引数にouterを実行した戻り値を変数decoratedに格納しています. fooを実行すると1が返ってきますが, outerを被せたdecoratedではそれに1プラスされて2が返ってきます. 言ってみればdecoratedは, fooのデコレーション版(foo + 何かの処理)といえます.
実際に有用なデコレータを使う際には, decoratedのように別の変数を用意せずfooそのものを置き換えてしまうことが多いです. つまり下のように.
>>> foo = outer(foo)
もう元のfooは呼ばれず, 常にデコレーションされたfooが戻ることになりますね. もう少し実用的な例も見てみましょう.
とある座標のオブジェクトを保持するライブラリを使っているとします. そのオブジェクトはxとyの座標ペアを保持していますが, 残念ながら足し算や引き算など数字の処理機能を持っていません. しかし我々はこのライブラリを用いて大量の計算処理をする必要があり, ライブラリのソースを改編することも好ましくない状況だとします. どうすれば良いでしょうか?
アプローチとしては下のようにadd, subのような関数を作ってやればよいでしょう.
>>> class Coordinate(object):
... def __init__(self, x, y):
... self.x = x
... self.y = y
... def __repr__(self):
... return "Coord: " + str(self.__dict__)
>>> def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)
>>> def sub(a, b):
... return Coordinate(a.x - b.x, a.y - b.y)
>>> one = Coordinate(100, 200)
>>> two = Coordinate(300, 200)
>>> add(one, two)
Coord: {'y': 400, 'x': 400}
ここでたとえば「扱う座標系は0が下限である必要がある」といったチェック処理が必要だとしたらどうしますか?
つまり, 現状では
>>> one = Coordinate(100, 200)
>>> two = Coordinate(300, 200)
>>> three = Coordinate(-100, -100)
>>> sub(one, two)
Coord: {'y': 0, 'x': -200}
>>> add(one, three)
Coord: {'y': 100, 'x': 0}
のようになりますが, sub(one, two)は(0, 0)を, add(one, three)は(100, 200)を返して欲しいということです. それぞれの関数に下限のチェックを入れていくということも考えられますが, ここでデコレータを使ってチェック処理を一元化してみましょう!
>>> def wrapper(func):
... def checker(a, b):
... if a.x < 0 or a.y < 0:
... a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
... if b.x < 0 or b.y < 0:
... b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
... ret = func(a, b)
... if ret.x < 0 or ret.y < 0:
... ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
... return ret
... return checker
>>> add = wrapper(add)
>>> sub = wrapper(sub)
>>> sub(one, two)
Coord: {'y': 0, 'x': 0}
>>> add(one, three)
Coord: {'y': 200, 'x': 100}
前の foo = outer(foo) とやっていることは変わりませんが, 有用なチェック機構をパラメータと関数の処理結果に対して適用することができています.
Step.10 @シンボルの適用
Pythonでは, デコレータの記述に関して@記号を用いたシンタックスシュガーが用意されています. すなわち
>>> add = wrapper(add)
という記述は,
>>> @wrapper
... def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)
という形で記述できます.
どうでしょう. ここまで読んで, classmethod や staticmethod のように有用なデコレータを自分で作ることはなかなかレベルが高い話ですが, 少なくともデコレータを使うのはそんなに難しくない - ただ @decoratorname を前置してやるだけだ! - と思っていただけると幸いです.
Step.11 *args と **kwargs
上で書いたデコレータwrapperは有用ですが, パラメータが2つという限られた関数にしか適用できません. 今回はそれでも良いのですが, もっとあらゆる関数に適用できるようなデコレータを書きたいと思ったらどうすれば良いでしょうか?
Pythonにはこれをサポートする機能も用意されています. 詳細は公式のドキュメントを読むのが良いですが, 関数を定義する際にパラメータに*(アスタリスク)を付けてやると任意の数の必須パラメータを受け付けることができます.
>>> def one(*args):
... print args
>>> one()
()
>>> one(1, 2, 3)
(1, 2, 3)
>>> def two(x, y, *args):
... print x, y, args
>>> two('a', 'b', 'c')
a b ('c',)
任意のパラメータ部分に関してはリストで渡されているのがわかりますね. また定義時ではなく呼び出し時に引数に*を付けてやると, 既にリストやタプルになった引数をアンパックして固定引数に適用してくれます.
>>> def add(x, y):
... return x + y
>>> lst = [1,2]
>>> add(lst[0], lst[1]) #1
3
>>> add(*lst) #2 <- #1と全く同じ意味を指します
3
また**(アスタリスク2個)という記法もあります. こちらはリストではなく辞書形式に対応しています.
>>> def foo(**kwargs):
... print kwargs
>>> foo()
{}
>>> foo(x=1, y=2)
{'y': 2, 'x': 1}
**kwargsを関数定義に使うことは「全ての明示的に指定していないパラメータはkwargsという名前の辞書に格納される」ことを意味します. *argsと同じく関数呼び出し時のアンパックにも対応しています.
>>> dct = {'x': 1, 'y': 2}
>>> def bar(x, y):
... return x + y
>>> bar(**dct)
3
Step.12 ジェネリックなデコレータ
上の機能を用いて, 関数の引数をログに出力するデコレータを書いてみましょう. 簡略化のためログ出力はstdoutにprintしています.
>>> def logger(func):
... def inner(*args, **kwargs): #1
... print "Arguments were: %s, %s" % (args, kwargs)
... return func(*args, **kwargs) #2
... return inner
#1でinner関数は任意の個数, 形式のパラメータを取ることができ, #2でそれをアンパックして引数として渡すことができていることに注目してください. これによりどのような関数に対してもデコレータloggerを適用することができます.
>>> @logger
... def foo1(x, y=1):
... return x * y
>>> @logger
... def foo2():
... return 2
>>> foo1(5, 4)
Arguments were: (5, 4), {}
20
>>> foo1(1)
Arguments were: (1,), {}
1
>>> foo2()
Arguments were: (), {}
2
より詳細が知りたい人のために
最後の例が理解できていれば, あなたはデコレータについて理解できたことになります! わからなければ前のステップに戻って何度でも読み返してみましょう.
もっと学習したい方はBruce Eckelの書いた下記素晴らしいエッセイを読むといいでしょう.
Decorators I: Introduction to Python Decorators
Python Decorators II: Decorator Arguments
(*)callableとは引数を取って結果を返す, 呼び出し可能なオブジェクトの総称を指します. functionはもちろんclassやmethod, generatorなどもcallableです.
Step1. 関数
>>> def foo():
... return 1
...
>>> foo()
1
これは基本ですね. Pythonにおいて関数はdefキーワードにより関数名とパラメータのリスト(任意)とともに定義できます.また括弧付きで名前を指定することで実行できます.
Step2. スコープ
Pythonでは関数を作ると新しいスコープが作られます.言い方を変えるとそれぞれの関数がそれぞれに名前空間を持つということです.
Pythonではこれらを確認することのできる組み込み関数も用意されていて, locals()で自身の持つローカルな名前空間の値を辞書形式で返却します.
>>> def foo(arg):
... x = 10
... print locals()
...
>>> foo(20)
{'x': 10, 'arg': 20}
またグローバルな名前空間についてはglobals()で同様に確認ができます.
>>> y = 30
>>> globals()
{..., 'y': 30} #Pythonが自動的に作るグローバル変数が他にも表示されるが省略
Step3. 変数の解決規則
Pythonにおける変数の解決ルールは
作成の際には常に新しい変数がその名前空間の中に作られる
参照は同じ名前空間内を検索し, 無ければ外側に検索を広げていく
というものです.関数のローカルスコープでグローバルスコープの変数を参照してみましょう.
>>> text = "I am global!"
>>> def foo():
... print text #1
...
>>> foo()
I am global!
関数の外側で定義したtextの内容がきちんと表示されていますね.#1ではまず関数内のローカル変数を探し, 無いので同じtextという名前のグローバル変数を探しにいっています.
では今度は, 関数の外側で定義した変数を, 関数内で変更してみましょう.
>>> text = "I am global!"
>>> def foo():
... text = "I am local!" #2
... print locals()
...
>>> foo()
{'text': 'I am local!'}
>>> text
'I am global!'
foo()が呼ばれた時にはtextの内容として関数内で代入した値がセットされていますが, 外側のグローバル変数のtextの値は変わっていません. #2では実際のところグローバル変数を探しに行かず, 関数foo内に新しいローカル変数textが作られているのです.
つまり関数の内側ではグローバル変数は参照はできるものの代入はできない, ということになります。
Step4. 変数のライフタイム
スコープだけでなくライフタイムについても知っておく必要があります.
>>> def foo():
... x = 1
...
>>> foo()
>>> print x #1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
ここでエラーが起こっているのは, 上述のスコープの問題だけではありません. 名前空間は関数fooが呼ばれる都度作られ, 処理が終わると無くなってしまいます.つまり上の例では#1のタイミングでは文字通りxという変数はどこにも存在していない, ということです.
Step5. 関数の引数とパラメータ
Pythonでは関数に引数を与えることができます. 定義時のパラメータの名前が, ローカル変数の名前として使われます.
>>> def foo(x):
... print locals()
>>> foo(1)
{'x': 1} # パラメータxがローカル変数名として使われている
Pythonでは関数にパラメータを設定したり, 呼び出し時に引数を与える様々な方法が提供されています. パラメータには必須パラメータと任意となるデフォルトパラメータがあります.
>>> def foo(x, y=0): # 1
... return x - y
>>> foo(3, 1) # 2
2
>>> foo(3) # 3
3
>>> foo() # 4
Traceback (most recent call last):
...
TypeError: foo() takes at least 1 argument (0 given)
>>> foo(y=1, x=3) # 5
2
#1の例ではxがパラメータ, デフォルトの値を指定しているyがデフォルトパラメータになります.#2が通常の関数使用例ですが, #3のようにデフォルトパラメータについては省略することも可能です. 省略された引数はデフォルトの値(この場合0)を取ります.
またPythonについては名前付き引数も使えるので, 名前を指定することで順番を気にせず引数を指定することもできます(#4). Pythonにおける引数はただの辞書だと理解していれば納得のいく動きです.
Step6. 関数のネスト
Pythonでは関数内にネストして関数を定義できます.
>>> def outer():
... x = 1
... def inner():
... print x # 1
... inner() # 2
...
>>> outer()
1
ルールはこれまで見てきたものと同じです. つまり#1ではローカル変数xを探すが見つからないので外側の名前空間を探し, outer内で定義されあているxを参照します.また#2ではinner()を呼び出していますが, ここで大切なのは innerというのも変数名の1つにすぎず, 解決規則に基づきouter内の名前空間内の定義を探して呼び出されている ということです.
Step7. 関数はPythonにおいてファーストクラスオブジェクトである
Pythonでは関数自身もまたオブジェクトにすぎません.
>>> issubclass(int, object) # Python内の全てのオブジェクトは同じ共通のクラスを継承して作られている
True
>>> def foo():
... pass
>>> foo.__class__
<type 'function'>
>>> issubclass(foo.__class__, object)
True
これが何を意味するかというと, 関数を一般的な他の変数と何らかわりなく扱える - つまり他の関数の引数として与えたり, 関数の戻り値として使うことができるということです.
>>> def add(x, y):
... return x + y
>>> def sub(x, y):
... return x - y
>>> def apply(func, x, y):
... return func(x, y)
>>> apply(add, 2, 1)
3
>>> apply(sub, 2, 1)
1
上の例では関数applyはパラメータとして指定された関数の実行結果を戻り値とするようになっていて, 関数add, subが引数として(他の変数と何ら変わりなく)与えられているのがわかります.
次の例はどうでしょうか.
>>> def outer():
... def inner():
... print "Inside inner"
... return inner # 1
...
>>> foo = outer() #2
>>> foo
<function inner at 0x...>
>>> foo()
Inside inner
上のapplyの例と異なるのは, #1で戻り値として実行結果ではなく関数そのものを指定しているということです.(inner()ではなくinnerを与えている)
これは#2のように普通に代入可能で, fooに関数が入っていて実行することもできることがわかります.
Step.8 クロージャ
上の例を少しだけ変えて見てみましょう.
>>> def outer():
... x = 1
... def inner():
... print x
... return inner
>>> foo = outer()
>>> foo.func_closure
(<cell at 0x...: int object at 0x...>,)
innerはouterによって返される関数で, fooに格納され, foo()により実行可能です...本当に?
Pythonの変数解決規則には完璧に従っていますが, ライフサイクルはどうなっていますか?変数xはouter関数が実行されている間のみ存在しています. ここではouter関数の処理が終わった後にinner関数がfooに代入されているので, foo()は実行できないのではないですか?
…この予想に反して, foo()は実行可能です。PythonがFunction clojures(クロージャ)の機能を持っているからで, これは グローバルスコープ以外で定義された関数(この場合inner)が, 「定義時」の自分を囲むスコープの情報を記憶している というものです. 実際に記憶されている事が上のようにfunc_closureプロパティを呼び出すことで確認できます.
「定義時」と書いたことを思い出してください. inner関数はouter関数が呼び出されるたびに新しく定義されています.
>>> def outer(x):
... def inner():
... print x
... return inner
>>> print1 = outer(1)
>>> print2 = outer(2)
>>> print1()
1
>>> print2()
2
上の例ではprint1やprint2に直接値を引数として入れなくても, それぞれの内部のinner関数が何の値を出力すべきかを記憶しているのです. これを利用して固定の引数を取るようカスタマイズした関数を生成することもできるということですね.
Step.9 デコレータ
いよいよデコレータの話に入ります.
ここまでの話を踏まえて先に結論から言うと, デコレータとは「関数を引数に取り, 引き換えに新たな関数を返すcallable(*)」です.
>>> def outer(some_func):
... def inner():
... print "before some_func"
... ret = some_func() #1
... return ret + 1
... return inner
>>> def foo():
... return 1
>>> decorated = outer(foo) #2
>>> decorated()
before some_func
2
1つ1つ理解していきましょう.
ここでパラメータとしてsome_funcを取るouterという関数を定義しています. そしてouterの中でさらにinnerという内部関数を定義しています.
innerは文字列をprintした後, #1で返却する値を取得しています. some_funcはouterが呼び出されるごとに異なる値を取りえますが, ここではそれが何であれとりあえず実行(call)し, その実行結果に1を加えた値を返却します.
最後にouter関数はinner関数そのものを返却します.
#2ではsome_funcとしてfooを引数にouterを実行した戻り値を変数decoratedに格納しています. fooを実行すると1が返ってきますが, outerを被せたdecoratedではそれに1プラスされて2が返ってきます. 言ってみればdecoratedは, fooのデコレーション版(foo + 何かの処理)といえます.
実際に有用なデコレータを使う際には, decoratedのように別の変数を用意せずfooそのものを置き換えてしまうことが多いです. つまり下のように.
>>> foo = outer(foo)
もう元のfooは呼ばれず, 常にデコレーションされたfooが戻ることになりますね. もう少し実用的な例も見てみましょう.
とある座標のオブジェクトを保持するライブラリを使っているとします. そのオブジェクトはxとyの座標ペアを保持していますが, 残念ながら足し算や引き算など数字の処理機能を持っていません. しかし我々はこのライブラリを用いて大量の計算処理をする必要があり, ライブラリのソースを改編することも好ましくない状況だとします. どうすれば良いでしょうか?
アプローチとしては下のようにadd, subのような関数を作ってやればよいでしょう.
>>> class Coordinate(object):
... def __init__(self, x, y):
... self.x = x
... self.y = y
... def __repr__(self):
... return "Coord: " + str(self.__dict__)
>>> def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)
>>> def sub(a, b):
... return Coordinate(a.x - b.x, a.y - b.y)
>>> one = Coordinate(100, 200)
>>> two = Coordinate(300, 200)
>>> add(one, two)
Coord: {'y': 400, 'x': 400}
ここでたとえば「扱う座標系は0が下限である必要がある」といったチェック処理が必要だとしたらどうしますか?
つまり, 現状では
>>> one = Coordinate(100, 200)
>>> two = Coordinate(300, 200)
>>> three = Coordinate(-100, -100)
>>> sub(one, two)
Coord: {'y': 0, 'x': -200}
>>> add(one, three)
Coord: {'y': 100, 'x': 0}
のようになりますが, sub(one, two)は(0, 0)を, add(one, three)は(100, 200)を返して欲しいということです. それぞれの関数に下限のチェックを入れていくということも考えられますが, ここでデコレータを使ってチェック処理を一元化してみましょう!
>>> def wrapper(func):
... def checker(a, b):
... if a.x < 0 or a.y < 0:
... a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
... if b.x < 0 or b.y < 0:
... b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
... ret = func(a, b)
... if ret.x < 0 or ret.y < 0:
... ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
... return ret
... return checker
>>> add = wrapper(add)
>>> sub = wrapper(sub)
>>> sub(one, two)
Coord: {'y': 0, 'x': 0}
>>> add(one, three)
Coord: {'y': 200, 'x': 100}
前の foo = outer(foo) とやっていることは変わりませんが, 有用なチェック機構をパラメータと関数の処理結果に対して適用することができています.
Step.10 @シンボルの適用
Pythonでは, デコレータの記述に関して@記号を用いたシンタックスシュガーが用意されています. すなわち
>>> add = wrapper(add)
という記述は,
>>> @wrapper
... def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)
という形で記述できます.
どうでしょう. ここまで読んで, classmethod や staticmethod のように有用なデコレータを自分で作ることはなかなかレベルが高い話ですが, 少なくともデコレータを使うのはそんなに難しくない - ただ @decoratorname を前置してやるだけだ! - と思っていただけると幸いです.
Step.11 *args と **kwargs
上で書いたデコレータwrapperは有用ですが, パラメータが2つという限られた関数にしか適用できません. 今回はそれでも良いのですが, もっとあらゆる関数に適用できるようなデコレータを書きたいと思ったらどうすれば良いでしょうか?
Pythonにはこれをサポートする機能も用意されています. 詳細は公式のドキュメントを読むのが良いですが, 関数を定義する際にパラメータに*(アスタリスク)を付けてやると任意の数の必須パラメータを受け付けることができます.
>>> def one(*args):
... print args
>>> one()
()
>>> one(1, 2, 3)
(1, 2, 3)
>>> def two(x, y, *args):
... print x, y, args
>>> two('a', 'b', 'c')
a b ('c',)
任意のパラメータ部分に関してはリストで渡されているのがわかりますね. また定義時ではなく呼び出し時に引数に*を付けてやると, 既にリストやタプルになった引数をアンパックして固定引数に適用してくれます.
>>> def add(x, y):
... return x + y
>>> lst = [1,2]
>>> add(lst[0], lst[1]) #1
3
>>> add(*lst) #2 <- #1と全く同じ意味を指します
3
また**(アスタリスク2個)という記法もあります. こちらはリストではなく辞書形式に対応しています.
>>> def foo(**kwargs):
... print kwargs
>>> foo()
{}
>>> foo(x=1, y=2)
{'y': 2, 'x': 1}
**kwargsを関数定義に使うことは「全ての明示的に指定していないパラメータはkwargsという名前の辞書に格納される」ことを意味します. *argsと同じく関数呼び出し時のアンパックにも対応しています.
>>> dct = {'x': 1, 'y': 2}
>>> def bar(x, y):
... return x + y
>>> bar(**dct)
3
Step.12 ジェネリックなデコレータ
上の機能を用いて, 関数の引数をログに出力するデコレータを書いてみましょう. 簡略化のためログ出力はstdoutにprintしています.
>>> def logger(func):
... def inner(*args, **kwargs): #1
... print "Arguments were: %s, %s" % (args, kwargs)
... return func(*args, **kwargs) #2
... return inner
#1でinner関数は任意の個数, 形式のパラメータを取ることができ, #2でそれをアンパックして引数として渡すことができていることに注目してください. これによりどのような関数に対してもデコレータloggerを適用することができます.
>>> @logger
... def foo1(x, y=1):
... return x * y
>>> @logger
... def foo2():
... return 2
>>> foo1(5, 4)
Arguments were: (5, 4), {}
20
>>> foo1(1)
Arguments were: (1,), {}
1
>>> foo2()
Arguments were: (), {}
2
より詳細が知りたい人のために
最後の例が理解できていれば, あなたはデコレータについて理解できたことになります! わからなければ前のステップに戻って何度でも読み返してみましょう.
もっと学習したい方はBruce Eckelの書いた下記素晴らしいエッセイを読むといいでしょう.
Decorators I: Introduction to Python Decorators
Python Decorators II: Decorator Arguments
(*)callableとは引数を取って結果を返す, 呼び出し可能なオブジェクトの総称を指します. functionはもちろんclassやmethod, generatorなどもcallableです.
2014年12月24日水曜日
発音基礎は「ア・エ・イ・ウ・エ・オ・ア・オ」
最初に「何ができないのかを分かる」ための滑舌トレーニングします。「発音基礎」や「早口言葉」を声に出して読み、自らの声に耳を傾けてください。前回練習した発声も意識してくださいね。
滑舌トレーニング(発音基礎)
まずは「ア・エ・イ・ウ・エ・オ・ア・オ」から始めましょう。
アナウンサーや役者の発音練習は、「ア・イ・ウ・エ・オ」ではなく「ア・エ・イ・ウ・エ・オ・ア・オ」と声を出します。この配列は、滑舌を良くし、正しい口の形を意識できるのです。
練習法は3段階です。苦手な音や行があったら、チェックしてください。
1 ア、エ、イ、ウ、エ、オ、ア、オ
一音一音を区切って、リズミカルにはっきり発音します
2 ア〜エ〜イ〜ウ〜エ〜オ〜ア〜オ〜
全ての母音を伸ばしつつ、一息で発音します。
3 アエイウエオアオ
最初はゆっくり、だんだん早くして、早口言葉のように一息で発音します
次のリストを、それぞれ3段階のパターンで発声しましょう。
アエイウエオアオ カケキクケコカコ
サセシスセソサソ タテチツテトタト
ナネニヌネノナノ ハヘヒフヘホハホ
マメミムメモマモ ヤエイユエヨヤヨ
ラレリルレロラロ ワエイウエヲワヲ
ガゲギグゲゴガゴ カ゜ケ゜キ゜ク゜ケ゜コ゜カ゜コ゜
ザゼジズゼゾザゾ ダデヂヅデドダド
バベビブベボバボ パペピプペポパポ
「カ゜ケ゜キ゜ク゜ケ゜コ゜カ゜コ゜」という見慣れない表記があります。
これは「鼻濁音(びだくおん)」です。「ガギグゲゴ」をそのまま発音すると耳障りなので、アナウンサーや役者など話のプロは、ガ行を鼻に抜いて柔らかく発音します。
原則、単語の中や末尾のガ行は鼻濁音で発音します。「映画館(エイカ゜カン)」「音楽(オンカ゜ク)」「賞味期限(ショウミキケ゜ン)」などです。他にも「私が〜○○したのですが〜」の「が」は「カ゜(鼻濁音)」です。
鼻濁音が分からない方は、ニュースやナレーションを注意深く聞いてみましょう。お薦めなのは、フジテレビ系列の朝の情報番組「めざましテレビ」の軽部真一アナウンサーです。軽部さんは、鼻濁音を明確に出しているので、良いお手本になります。
今回の映像では、割り箸を使ったトレーニングを紹介します。
目的は、舌の動きをチェックすることと、割り箸をくわえて負荷をかけることで、口の周りと舌の筋肉を鍛えることです。スポーツジムで筋肉を付けるためにバーベルやマシンで負荷をかけるのと同じ仕組みです。
声帯、口の周り、舌もそれぞれ筋肉です。繰り返し練習すれば、必ず努力に応えてくれますよ。
滑舌トレーニング(早口言葉)
発音トレーニングで思い浮かぶのが、「早口言葉」です。アナウンサーが早口言葉にチャレンジするシーンを、テレビなどで見たことがある人も多いでしょう。
早口言葉は、最初から早く話すのではなく、まずは「ゆっくりと」「一語一語」「明確に音を出すこと」を意識することから始めます。苦手な文章があれば、チェックします。慣れてきたら、だんだん早くしてみましょう。
あやしみと、あやしむべきを、あやしまず。あやしからぬを、あやしむ、あやし
川から上がった河童さんは、皿が乾いたから、頭がなかなか働かなかった。何だか頭がガンガンなった
歌うたいが、歌うたいに来て、歌うたえというが、歌うたいのように、歌うたえれば歌うたうが、歌うたいのようには歌うたえぬから、歌うたわぬ
お客が柿ョむきゃ飛脚が柿ョ食う。飛脚が柿ョむきゃお客が柿ョ食う。お客も飛脚もよく柿ョ食う飛脚
みみずにょろにょろ、三にょろにょろ。合わせてにょろにょろ、六にょろにょろ
カエルぴょこぴょこ、三ぴょこぴょこ。合わせてぴょこぴょこ、六ぴょこぴょこ
踊りおどるなら、踊りの道理を習って、踊りの道理通りに、踊りをおどれ
とろろ汁をとる苦労より、とろろ汁からとろっとする、とろろ汁をとる苦労
笑わば笑え、わらわは笑われるいわれはないわい
わしの家のわしの木に、鷲が止まったから、わしが鉄砲で撃ったら、鷲も驚いたがわしも驚いた
ポイントは、最初から最後まで「同じ速度」で「同じ声の大きさ」で読むことです。実は、人は苦手な発音や言葉の組み合わせになると、無意識に話す速度が速くなり、声も小さくなりがちなのです。
「滑舌に自信がないけれど一人では確認しにくい」という場合は、ボイスレコーダーに録音することをお勧めします。スマートフォンの録音機能を利用すると簡単です。
想像していた声とイメージが違うことが多いため、自分の声を聞きたくないという方も多いようです。しかし、自分の声を客観的に知ることは、とても効果的なのです。「あ、こういう風に聞こえるのか」「あれー、イメージと違うな」などが分かります。また、トレーニングを重ねたら、最初に録音した声と比較すると、声の変化を実感できます。
滑舌トレーニング(発音基礎)
まずは「ア・エ・イ・ウ・エ・オ・ア・オ」から始めましょう。
アナウンサーや役者の発音練習は、「ア・イ・ウ・エ・オ」ではなく「ア・エ・イ・ウ・エ・オ・ア・オ」と声を出します。この配列は、滑舌を良くし、正しい口の形を意識できるのです。
練習法は3段階です。苦手な音や行があったら、チェックしてください。
1 ア、エ、イ、ウ、エ、オ、ア、オ
一音一音を区切って、リズミカルにはっきり発音します
2 ア〜エ〜イ〜ウ〜エ〜オ〜ア〜オ〜
全ての母音を伸ばしつつ、一息で発音します。
3 アエイウエオアオ
最初はゆっくり、だんだん早くして、早口言葉のように一息で発音します
次のリストを、それぞれ3段階のパターンで発声しましょう。
アエイウエオアオ カケキクケコカコ
サセシスセソサソ タテチツテトタト
ナネニヌネノナノ ハヘヒフヘホハホ
マメミムメモマモ ヤエイユエヨヤヨ
ラレリルレロラロ ワエイウエヲワヲ
ガゲギグゲゴガゴ カ゜ケ゜キ゜ク゜ケ゜コ゜カ゜コ゜
ザゼジズゼゾザゾ ダデヂヅデドダド
バベビブベボバボ パペピプペポパポ
「カ゜ケ゜キ゜ク゜ケ゜コ゜カ゜コ゜」という見慣れない表記があります。
これは「鼻濁音(びだくおん)」です。「ガギグゲゴ」をそのまま発音すると耳障りなので、アナウンサーや役者など話のプロは、ガ行を鼻に抜いて柔らかく発音します。
原則、単語の中や末尾のガ行は鼻濁音で発音します。「映画館(エイカ゜カン)」「音楽(オンカ゜ク)」「賞味期限(ショウミキケ゜ン)」などです。他にも「私が〜○○したのですが〜」の「が」は「カ゜(鼻濁音)」です。
鼻濁音が分からない方は、ニュースやナレーションを注意深く聞いてみましょう。お薦めなのは、フジテレビ系列の朝の情報番組「めざましテレビ」の軽部真一アナウンサーです。軽部さんは、鼻濁音を明確に出しているので、良いお手本になります。
今回の映像では、割り箸を使ったトレーニングを紹介します。
目的は、舌の動きをチェックすることと、割り箸をくわえて負荷をかけることで、口の周りと舌の筋肉を鍛えることです。スポーツジムで筋肉を付けるためにバーベルやマシンで負荷をかけるのと同じ仕組みです。
声帯、口の周り、舌もそれぞれ筋肉です。繰り返し練習すれば、必ず努力に応えてくれますよ。
滑舌トレーニング(早口言葉)
発音トレーニングで思い浮かぶのが、「早口言葉」です。アナウンサーが早口言葉にチャレンジするシーンを、テレビなどで見たことがある人も多いでしょう。
早口言葉は、最初から早く話すのではなく、まずは「ゆっくりと」「一語一語」「明確に音を出すこと」を意識することから始めます。苦手な文章があれば、チェックします。慣れてきたら、だんだん早くしてみましょう。
あやしみと、あやしむべきを、あやしまず。あやしからぬを、あやしむ、あやし
川から上がった河童さんは、皿が乾いたから、頭がなかなか働かなかった。何だか頭がガンガンなった
歌うたいが、歌うたいに来て、歌うたえというが、歌うたいのように、歌うたえれば歌うたうが、歌うたいのようには歌うたえぬから、歌うたわぬ
お客が柿ョむきゃ飛脚が柿ョ食う。飛脚が柿ョむきゃお客が柿ョ食う。お客も飛脚もよく柿ョ食う飛脚
みみずにょろにょろ、三にょろにょろ。合わせてにょろにょろ、六にょろにょろ
カエルぴょこぴょこ、三ぴょこぴょこ。合わせてぴょこぴょこ、六ぴょこぴょこ
踊りおどるなら、踊りの道理を習って、踊りの道理通りに、踊りをおどれ
とろろ汁をとる苦労より、とろろ汁からとろっとする、とろろ汁をとる苦労
笑わば笑え、わらわは笑われるいわれはないわい
わしの家のわしの木に、鷲が止まったから、わしが鉄砲で撃ったら、鷲も驚いたがわしも驚いた
ポイントは、最初から最後まで「同じ速度」で「同じ声の大きさ」で読むことです。実は、人は苦手な発音や言葉の組み合わせになると、無意識に話す速度が速くなり、声も小さくなりがちなのです。
「滑舌に自信がないけれど一人では確認しにくい」という場合は、ボイスレコーダーに録音することをお勧めします。スマートフォンの録音機能を利用すると簡単です。
想像していた声とイメージが違うことが多いため、自分の声を聞きたくないという方も多いようです。しかし、自分の声を客観的に知ることは、とても効果的なのです。「あ、こういう風に聞こえるのか」「あれー、イメージと違うな」などが分かります。また、トレーニングを重ねたら、最初に録音した声と比較すると、声の変化を実感できます。
2014年12月16日火曜日
locals と globals
Python は、辞書を用いてローカル変数やグローバル変数へアクセスするための 二つのビルトイン関数、locals と globals を持っている。
locals を覚えてるだろうか? はじめて見たのは以下のコードにおいてあろう:
def unknown_starttag(self, tag, attrs):
strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs])
self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
いや、待ってほしい、読者はまだ locals について学習することはできない。 まず最初に、名前空間について、学ぶ必要があるのだ。 これは無味乾燥なものかもしれないが、重要なので注意を払ってほしい。
Python は、変数を追跡し続けるために、名前空間と呼ばれるものを用いている。 名前空間は、単に辞書のようなものであり、そのキーは「変数名」、値は「変数の値」である。 実際、すぐ確認できるのだが、Python の辞書と同じように名前空間にアクセスすることができる。
Python プログラムのいかなるポイントにおいても、いくつかの名前空間の変数が存在する。 それぞれの関数は それ自身の名前空間を持っており、それが(引数やローカル変数といった)関数の変数を追跡し続ける。 それぞれのモジュールは、「グローバルな名前空間」と呼ばれる自分自身の名前空間をもっており、それによって、(関数、クラス、他のすべでのインポートされたモジュール、モジュール・レベルの変数、定数といった)モジュール変数を追跡し続ける。 そして、ビルトイン関数や例外を保持する「ビルトイン名前空間」が存在する。
コードのある行が変数 x の値を問い合わせたとき、Python は その時点でアクセス可能なすべての名前空間の中を順番に、その変数を検索する:
1. ローカルな名前空間 --- 現在の関数やクラス・メソッドに特有な名前空間のこと。 もしも関数がローカル変数 x を定義したり、引数 x を持っていると、Python はこれを使い、検索をストップする。
2. グローバルな名前空間 --- 現在のモジュールに特有な名前空間のこと。 もしもあるモジュールがx という変数、 xという関数、あるいは、x というクラスを定義していた場合、Python はこれを用い、検索をストップする。
3. ビルトイン名前空間 --- すべてのモジュールに対してグローバルな名前空間のこと。 最後の手段として、Python は、x がビルトイン関数か変数ではないかと推測する。
もしも Python が x をいかなる名前空間においても発見出来なかった場合、ギブアップし、There is no variable named 'x' というメッセージとともに NameError を返す。 この挙動は、例3.18で見たとおりである。 読者は、解放された変数を参照する際、Python が このエラーを返す前にどれだけ多くの仕事をこなしたかについて、感謝してはこなかったであろう。
Python 2.2 は、名前空間の検索に影響するような、微妙ではあるが重要な変更を行った: それは、ネストされたスコープである。 Python 2.2 以前のバージョンでは、ネストされた関数やlambda 関数の中の変数を参照する際、Python はまず現在の(ネストされた、あるいは、lambda)関数の名前空間を検索し、次に、親の関数の名前空間を検索し、それから、モジュールの名前空間を検索していた。 Python 2.1 は、どちらの方法でも動作する; デフォルトでは、Python 2.0 のように動作するが、コードの先頭に次の行を付け加えることにより、そのモジュールを、Python 2.2 のように動作させることも可能である:
from __future__ import nested_scopes
まだ混乱しているだろうか? おちこむことはない! 約束するが、これは非常にクールなことである。 Python における、他の多くの事柄と同じく、名前空間は、プログラムの実行時に直接アクセス可能である。 しかし、どうやって? ローカルの名前空間へは、ビルトインされた locals 関数によって、アクセスできる。 そして、(モジュラー・レベルでの)グローバルな名前空間には、ビルトインされた globals 関数によって、アクセスできる。
Example 8.10. locals の導入
>>> def foo(arg):
... x = 1
... print locals()
...
>>> foo(7)
{'arg': 7, 'x': 1}
>>> foo('bar')
{'arg': 'bar', 'x': 1}
関数 foo は、ローカルな名前空間に二つの変数を持っている; ひとつは arg であり、その値は関数に引き渡される。 そしてもうひとつは x であり、関数の中で定義されている。
locals は 「名前/値」ペアに関する辞書を返す。この辞書のキーは、変数名(文字列型)である。したがって、foo を 7 という引数で呼び出すと、この関数の二つのローカル変数(arg(7) と x(1) )を含む辞書を表示する。
Python は動的なタイピングをサポートしており、arg に対して簡単に文字列を渡せることを思い出してほしい; この関数(そして、locals の呼び出し)はうまく動作する。locals は、あらゆるデータ型の変数を取り扱える。
from module import と import module の違いを覚えているだろうか? import module では、モジュールそのものがインポートされていたが、それ自身の名前空間は保持されていた。したがって、そのモジュールが含むいかなる関数やアトリビュートに対しても、アクセスの際にはモジュール名が必要であった: module.function。しかし、from module import を用いると、本当に、特定の関数とそのアトリビュートを他のモジュールからインポートし、あなた自身がもっている名前空間に付け加えることになる。もともとのモジュールを参照することなく、関数名のみで直接アクセスができるのは、これが理由である。globals 関数を用いると、ここで起きていることを実際に眺めることができる。
Example 8.11. globals の導入
BaseHTMLProcessor.py の最下部にある、以下のコード・ブロックを見てほしい:
if __name__ == "__main__":
for k, v in globals().items():
print k, "=", v
おじけづくことはない、以前、このコードを読んだことを思い出そう。 globals 関数は辞書を返し、あなたは、items メソッドとマルチ・バリアブル・アサイメントを用いて、この辞書の中身について繰り返し反復を行った。 ここで新たに導入されたのは、globals 関数のみである。
ここで、スクリプトをコマンドラインから実行すると、以下のアウトプットが得られる。 (ただし、読者がPython をインストールした環境に応じて、このアウトプットは若干異なるかもしれないことに、注意してほしい。)
c:\docbook\dip\py> python BaseHTMLProcessor.py
SGMLParser = sgmllib.SGMLParser
htmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'>
BaseHTMLProcessor = __main__.BaseHTMLProcessor
__name__ = __main__
... rest of output omitted for brevity...
from module import によって、SGMLParser は sgmlib からインポートされた。これは、モジュールの名前空間へ直接とりこまれたことを意味し、実際、そうなっている。
これを、import によってインポートされた htmlentitiydefs と比べている。htmlentitydefsモジュール自身は名前空間の中にあるが、htmlentitydefs の中で定義された変数 entitydefs はそうでは無い。
このモジュールは、BaseHTMLProcessor という一つのクラスを定義しているのみであり、そうなっている。ここでの値はクラスそのものであり、クラスの特定のインスタンスでは無いことに注意せよ。
if __name__ トリックについて覚えているだろうか? モジュールを実行する際、(他のモジュールからのインポートに反して)、ビルトインの __name__ アトリビュートは 特殊な値 __main__ になる。 このモジュールは、コマンドラインからスクリプトとして実行されているので、__name__ は __main__ であり、これが、globals を表示する小さなコードが実行された理由である。
locals 関数と globals 関数を使うと、変数名を文字列として与えることにより、任意の変数の値を動的に取得することができる。 これは、関数名を文字列として与えることにより、任意の関数へアクセスすることを可能とする、getattr 関数の機能をうつしたものである。
locals と globals 関数にはもうひとつ重要な違いがあり、それが あなたに噛み付く前に学んでほしい。 それは、とにかく いつか あなたに噛み付くだろうが、すくなくともその時、既にそれを学んだことを思い出してほしい。
Example 8.12. locals はリード・オンリーであり、 globals はそうではない
def foo(arg):
x = 1
print locals()
locals()["x"] = 2
print "x=",x
z = 7
print "z=",z
foo(3)
globals()["z"] = 8
print "z=",z
foo は、引数 3 とともに呼び出されたので、これは {'arg': 3, 'x': 1} を表示するであろう。これは、何ら驚くべきことではない。
locals は辞書を返す関数であり、ここではその辞書の値を設定している。これにより、ローカル変数 x の値が 2 に変わると思うかもしれないが、しかし、そうではない。locals は、実際にローカルな名前空間を返しているわけではなく、そのコピーを返しているのである。したがって、それを変更してもローカルな名前空間の変数の値は変わらないのである。
x=2 ではなく、x=1 が表示される。
locals によってやけどした後なので、こうやっても z の値は変わらないと思うかもしれない。しかし、今度は変わるのである。Python の内部仕様の相違(これについては深追いしない。なぜなら、筆者も完全に理解しているわけでは無いので)により、globals は、名前空間のコピーではなく、名前空間そのもを返す: これは、locals とは正反対の挙動である。従って、globals が返した辞書へのあらゆる変更は、ただちにグローバル変数に影響を及ぼす。
z = 7 ではなく z = 8 が表示される。
locals を覚えてるだろうか? はじめて見たのは以下のコードにおいてあろう:
def unknown_starttag(self, tag, attrs):
strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs])
self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
いや、待ってほしい、読者はまだ locals について学習することはできない。 まず最初に、名前空間について、学ぶ必要があるのだ。 これは無味乾燥なものかもしれないが、重要なので注意を払ってほしい。
Python は、変数を追跡し続けるために、名前空間と呼ばれるものを用いている。 名前空間は、単に辞書のようなものであり、そのキーは「変数名」、値は「変数の値」である。 実際、すぐ確認できるのだが、Python の辞書と同じように名前空間にアクセスすることができる。
Python プログラムのいかなるポイントにおいても、いくつかの名前空間の変数が存在する。 それぞれの関数は それ自身の名前空間を持っており、それが(引数やローカル変数といった)関数の変数を追跡し続ける。 それぞれのモジュールは、「グローバルな名前空間」と呼ばれる自分自身の名前空間をもっており、それによって、(関数、クラス、他のすべでのインポートされたモジュール、モジュール・レベルの変数、定数といった)モジュール変数を追跡し続ける。 そして、ビルトイン関数や例外を保持する「ビルトイン名前空間」が存在する。
コードのある行が変数 x の値を問い合わせたとき、Python は その時点でアクセス可能なすべての名前空間の中を順番に、その変数を検索する:
1. ローカルな名前空間 --- 現在の関数やクラス・メソッドに特有な名前空間のこと。 もしも関数がローカル変数 x を定義したり、引数 x を持っていると、Python はこれを使い、検索をストップする。
2. グローバルな名前空間 --- 現在のモジュールに特有な名前空間のこと。 もしもあるモジュールがx という変数、 xという関数、あるいは、x というクラスを定義していた場合、Python はこれを用い、検索をストップする。
3. ビルトイン名前空間 --- すべてのモジュールに対してグローバルな名前空間のこと。 最後の手段として、Python は、x がビルトイン関数か変数ではないかと推測する。
もしも Python が x をいかなる名前空間においても発見出来なかった場合、ギブアップし、There is no variable named 'x' というメッセージとともに NameError を返す。 この挙動は、例3.18で見たとおりである。 読者は、解放された変数を参照する際、Python が このエラーを返す前にどれだけ多くの仕事をこなしたかについて、感謝してはこなかったであろう。
Python 2.2 は、名前空間の検索に影響するような、微妙ではあるが重要な変更を行った: それは、ネストされたスコープである。 Python 2.2 以前のバージョンでは、ネストされた関数やlambda 関数の中の変数を参照する際、Python はまず現在の(ネストされた、あるいは、lambda)関数の名前空間を検索し、次に、親の関数の名前空間を検索し、それから、モジュールの名前空間を検索していた。 Python 2.1 は、どちらの方法でも動作する; デフォルトでは、Python 2.0 のように動作するが、コードの先頭に次の行を付け加えることにより、そのモジュールを、Python 2.2 のように動作させることも可能である:
from __future__ import nested_scopes
まだ混乱しているだろうか? おちこむことはない! 約束するが、これは非常にクールなことである。 Python における、他の多くの事柄と同じく、名前空間は、プログラムの実行時に直接アクセス可能である。 しかし、どうやって? ローカルの名前空間へは、ビルトインされた locals 関数によって、アクセスできる。 そして、(モジュラー・レベルでの)グローバルな名前空間には、ビルトインされた globals 関数によって、アクセスできる。
Example 8.10. locals の導入
>>> def foo(arg):
... x = 1
... print locals()
...
>>> foo(7)
{'arg': 7, 'x': 1}
>>> foo('bar')
{'arg': 'bar', 'x': 1}
関数 foo は、ローカルな名前空間に二つの変数を持っている; ひとつは arg であり、その値は関数に引き渡される。 そしてもうひとつは x であり、関数の中で定義されている。
locals は 「名前/値」ペアに関する辞書を返す。この辞書のキーは、変数名(文字列型)である。したがって、foo を 7 という引数で呼び出すと、この関数の二つのローカル変数(arg(7) と x(1) )を含む辞書を表示する。
Python は動的なタイピングをサポートしており、arg に対して簡単に文字列を渡せることを思い出してほしい; この関数(そして、locals の呼び出し)はうまく動作する。locals は、あらゆるデータ型の変数を取り扱える。
from module import と import module の違いを覚えているだろうか? import module では、モジュールそのものがインポートされていたが、それ自身の名前空間は保持されていた。したがって、そのモジュールが含むいかなる関数やアトリビュートに対しても、アクセスの際にはモジュール名が必要であった: module.function。しかし、from module import を用いると、本当に、特定の関数とそのアトリビュートを他のモジュールからインポートし、あなた自身がもっている名前空間に付け加えることになる。もともとのモジュールを参照することなく、関数名のみで直接アクセスができるのは、これが理由である。globals 関数を用いると、ここで起きていることを実際に眺めることができる。
Example 8.11. globals の導入
BaseHTMLProcessor.py の最下部にある、以下のコード・ブロックを見てほしい:
if __name__ == "__main__":
for k, v in globals().items():
print k, "=", v
おじけづくことはない、以前、このコードを読んだことを思い出そう。 globals 関数は辞書を返し、あなたは、items メソッドとマルチ・バリアブル・アサイメントを用いて、この辞書の中身について繰り返し反復を行った。 ここで新たに導入されたのは、globals 関数のみである。
ここで、スクリプトをコマンドラインから実行すると、以下のアウトプットが得られる。 (ただし、読者がPython をインストールした環境に応じて、このアウトプットは若干異なるかもしれないことに、注意してほしい。)
c:\docbook\dip\py> python BaseHTMLProcessor.py
SGMLParser = sgmllib.SGMLParser
htmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'>
BaseHTMLProcessor = __main__.BaseHTMLProcessor
__name__ = __main__
... rest of output omitted for brevity...
from module import によって、SGMLParser は sgmlib からインポートされた。これは、モジュールの名前空間へ直接とりこまれたことを意味し、実際、そうなっている。
これを、import によってインポートされた htmlentitiydefs と比べている。htmlentitydefsモジュール自身は名前空間の中にあるが、htmlentitydefs の中で定義された変数 entitydefs はそうでは無い。
このモジュールは、BaseHTMLProcessor という一つのクラスを定義しているのみであり、そうなっている。ここでの値はクラスそのものであり、クラスの特定のインスタンスでは無いことに注意せよ。
if __name__ トリックについて覚えているだろうか? モジュールを実行する際、(他のモジュールからのインポートに反して)、ビルトインの __name__ アトリビュートは 特殊な値 __main__ になる。 このモジュールは、コマンドラインからスクリプトとして実行されているので、__name__ は __main__ であり、これが、globals を表示する小さなコードが実行された理由である。
locals 関数と globals 関数を使うと、変数名を文字列として与えることにより、任意の変数の値を動的に取得することができる。 これは、関数名を文字列として与えることにより、任意の関数へアクセスすることを可能とする、getattr 関数の機能をうつしたものである。
locals と globals 関数にはもうひとつ重要な違いがあり、それが あなたに噛み付く前に学んでほしい。 それは、とにかく いつか あなたに噛み付くだろうが、すくなくともその時、既にそれを学んだことを思い出してほしい。
Example 8.12. locals はリード・オンリーであり、 globals はそうではない
def foo(arg):
x = 1
print locals()
locals()["x"] = 2
print "x=",x
z = 7
print "z=",z
foo(3)
globals()["z"] = 8
print "z=",z
foo は、引数 3 とともに呼び出されたので、これは {'arg': 3, 'x': 1} を表示するであろう。これは、何ら驚くべきことではない。
locals は辞書を返す関数であり、ここではその辞書の値を設定している。これにより、ローカル変数 x の値が 2 に変わると思うかもしれないが、しかし、そうではない。locals は、実際にローカルな名前空間を返しているわけではなく、そのコピーを返しているのである。したがって、それを変更してもローカルな名前空間の変数の値は変わらないのである。
x=2 ではなく、x=1 が表示される。
locals によってやけどした後なので、こうやっても z の値は変わらないと思うかもしれない。しかし、今度は変わるのである。Python の内部仕様の相違(これについては深追いしない。なぜなら、筆者も完全に理解しているわけでは無いので)により、globals は、名前空間のコピーではなく、名前空間そのもを返す: これは、locals とは正反対の挙動である。従って、globals が返した辞書へのあらゆる変更は、ただちにグローバル変数に影響を及ぼす。
z = 7 ではなく z = 8 が表示される。
Python高度なimport
同じフォルダにhogehoge.pyというファイルがあったら
import hogehoge
と書くことでインポートできるし、
from hogehoge import *
と書けば、本文中でhogehoge.メソッド名なんて書かずに直接メソッド名だけでメソッドを呼び出せる。asで別名とか、まあPythonのモジュールインポートのしくみでも見てもらえるといいと思う。
以下にパッケージの話が出てこないのは話したい話を単純にするための仕様です。特に「モジュールを探す範囲を拡張」なんかは普通はパッケージの仕組みを使ったほうが簡単にできると思う。でもそれだけでは出来ないことをここでは解説したい。
同じディレクトリに置きたくない!ってこともあると思います。そういうときは
sys.path.append('パス')
としてやればそこも探してくれるようになります。基本的には絶対パス。
import sys,os
sys.path.append(os.pardir) #親フォルダを追加
from i3r import printnum, printstr
とか
import sys,os
dirpath = os.path.dirname(os.path.abspath(__file__))
datadir = 'data'
sys.path.append(dirpath+'/'+datadir)
from i3k import *
とか自由にどうぞ。os.path.dirname(os.path.abspath(__file__))を使ってディレクトリの絶対パスを取得することで、ユーザによる Python コードの変更が必要となるため、sys.path.append() の使用はお勧めしません。なんて言いがかりも避けられる。
メソッドの上書き
たとえばi3r.pyで
def printnum():
print(3)
def printstr():
print("r")
と書いていて、i3k.pyで
from i3r import printnum, printstr
def printstr():
print('k')
とするとprintstr()の結果は上書きされてkになり、printnum()はそのまま3が出力される。
変数でモジュール名を指定
import式と等価な組み込み関数に__import__がある。
これを使えば、動的に生成されたモジュールを呼び出すことができ、メタプログラミングの際に有用だ。例えば下記の様になる。
modname = 'i3k'
module = __import__(modname)
module.printnum()
module.printstr()
ではfrom ... import ... はどうやって書くかというと、
modname = 'i3k'
methods = ['printnum','printstr']
module = __import__(modname, globals(), locals(), methods, -1)
module.printnum()
module.printstr()
こんな感じでimportする関数を指定できる。問題はmodule.を付けなければいけない事。さっきみたいに上書きとかしたい時はどうするか?
modname = 'i3k'
methods = ['printnum','printstr']
module = __import__(modname, globals(), locals(), methods, -1)
printnum = module.printnum #module.無しで使いたかったらコレ
printstr = getattr(module,'printstr') #この書き方でも同等
printnum()
printstr()
こんな感じでローカル変数に持って来れる。しかし、こうやって各個上書きするのは面倒だろう。for文とかでできないか?
modname = 'i3k'
methods = ['printnum','printstr']
module = __import__(modname, globals(), locals(), methods, -1)
for x in methods:
locals()[x]=getattr(module,x)
printnum()
printstr()
そう。「ローカル変数に持って来」ればいいのだからこの手が使える。ここまで来たらfrom i3k import *のようにメソッド一括みたいなこともできるかな?
modname = 'i3k'
module = __import__(modname)
exceplist = ['__builtins__', '__doc__', '__file__', '__name__', '__package__']
for x in dir(module):
if x not in exceplist:
locals()[x]=getattr(module,x)
printnum()
printstr()
可読性の面からは全然お勧めできないね。dir(モジュール名)でモジュールの全attributeを列挙してくれるから、その中から一般的に上書きしちゃいけないモノリストを挙げて、それ以外を上書きしている。まあ、あくまでこういうこともできるってことで。こういうメタなことをする時に重要なのはBuilt-in Functionsの知識。__import__もgetattrもdirも組み込み関数。
Pythonで可変関数
さっきの
locals()[x]=getattr(module,x)
ってのは前述のように「ローカル変数に持って来」てるのだが、可変関数を作っていると見ることができる。同様に、右辺に来るのをただの値にすれば可変変数も作れる。PHPは可変変数が楽だよとよく言われるが、Pythonも難しくないです。
ちなみに「可変変数」って変だなあと思ったが、英語でも"Variable variables"らしくて"Dynamic variables"とも言うが「動的変数」って別物について使うらしいし、召喚変数とかどうだろう。
import hogehoge
と書くことでインポートできるし、
from hogehoge import *
と書けば、本文中でhogehoge.メソッド名なんて書かずに直接メソッド名だけでメソッドを呼び出せる。asで別名とか、まあPythonのモジュールインポートのしくみでも見てもらえるといいと思う。
以下にパッケージの話が出てこないのは話したい話を単純にするための仕様です。特に「モジュールを探す範囲を拡張」なんかは普通はパッケージの仕組みを使ったほうが簡単にできると思う。でもそれだけでは出来ないことをここでは解説したい。
同じディレクトリに置きたくない!ってこともあると思います。そういうときは
sys.path.append('パス')
としてやればそこも探してくれるようになります。基本的には絶対パス。
import sys,os
sys.path.append(os.pardir) #親フォルダを追加
from i3r import printnum, printstr
とか
import sys,os
dirpath = os.path.dirname(os.path.abspath(__file__))
datadir = 'data'
sys.path.append(dirpath+'/'+datadir)
from i3k import *
とか自由にどうぞ。os.path.dirname(os.path.abspath(__file__))を使ってディレクトリの絶対パスを取得することで、ユーザによる Python コードの変更が必要となるため、sys.path.append() の使用はお勧めしません。なんて言いがかりも避けられる。
メソッドの上書き
たとえばi3r.pyで
def printnum():
print(3)
def printstr():
print("r")
と書いていて、i3k.pyで
from i3r import printnum, printstr
def printstr():
print('k')
とするとprintstr()の結果は上書きされてkになり、printnum()はそのまま3が出力される。
変数でモジュール名を指定
import式と等価な組み込み関数に__import__がある。
これを使えば、動的に生成されたモジュールを呼び出すことができ、メタプログラミングの際に有用だ。例えば下記の様になる。
modname = 'i3k'
module = __import__(modname)
module.printnum()
module.printstr()
ではfrom ... import ... はどうやって書くかというと、
modname = 'i3k'
methods = ['printnum','printstr']
module = __import__(modname, globals(), locals(), methods, -1)
module.printnum()
module.printstr()
こんな感じでimportする関数を指定できる。問題はmodule.を付けなければいけない事。さっきみたいに上書きとかしたい時はどうするか?
modname = 'i3k'
methods = ['printnum','printstr']
module = __import__(modname, globals(), locals(), methods, -1)
printnum = module.printnum #module.無しで使いたかったらコレ
printstr = getattr(module,'printstr') #この書き方でも同等
printnum()
printstr()
こんな感じでローカル変数に持って来れる。しかし、こうやって各個上書きするのは面倒だろう。for文とかでできないか?
modname = 'i3k'
methods = ['printnum','printstr']
module = __import__(modname, globals(), locals(), methods, -1)
for x in methods:
locals()[x]=getattr(module,x)
printnum()
printstr()
そう。「ローカル変数に持って来」ればいいのだからこの手が使える。ここまで来たらfrom i3k import *のようにメソッド一括みたいなこともできるかな?
modname = 'i3k'
module = __import__(modname)
exceplist = ['__builtins__', '__doc__', '__file__', '__name__', '__package__']
for x in dir(module):
if x not in exceplist:
locals()[x]=getattr(module,x)
printnum()
printstr()
可読性の面からは全然お勧めできないね。dir(モジュール名)でモジュールの全attributeを列挙してくれるから、その中から一般的に上書きしちゃいけないモノリストを挙げて、それ以外を上書きしている。まあ、あくまでこういうこともできるってことで。こういうメタなことをする時に重要なのはBuilt-in Functionsの知識。__import__もgetattrもdirも組み込み関数。
Pythonで可変関数
さっきの
locals()[x]=getattr(module,x)
ってのは前述のように「ローカル変数に持って来」てるのだが、可変関数を作っていると見ることができる。同様に、右辺に来るのをただの値にすれば可変変数も作れる。PHPは可変変数が楽だよとよく言われるが、Pythonも難しくないです。
ちなみに「可変変数」って変だなあと思ったが、英語でも"Variable variables"らしくて"Dynamic variables"とも言うが「動的変数」って別物について使うらしいし、召喚変数とかどうだろう。
2014年12月15日月曜日
Metaprogramming
Objects are created by other objects: special objects called "classes" that we can set up to spit out objects that are configured to our liking.
Classes are just objects, and they can be modified the same way:
>>> class Foo: pass
...
>>> Foo.field = 42
>>> x = Foo()
>>> x.field
42
>>> Foo.field2 = 99
>>> x.field2
99
>>> Foo.method = lambda self: "Hi!"
>>> x.method()
'Hi!'
To modify a class, you perform operations on it like any other object. You can add and subtract fields and methods, for example. The difference is that any change you make to a class affects all the objects of that class, even the ones that have already been instantiated.
What creates these special "class" objects? Other special objects, called metaclasses.
The default metaclass is called type and in the vast majority of cases it does the right thing. In some situations, however, you can gain leverage by modifying the way that classes are produced ? typically by performing extra actions or injecting code. When this is the case, you can use metaclass programming to modify the way that some of your class objects are created.
It's worth re-emphasizing that in the vast majority of cases, you don't need metaclasses, because it's a fascinating toy and the temptation to use it everywhere can be overwhelming. Some of the examples in this chapter will show both metaclass and non-metaclass solutions to a problem, so you can see that there's usually another (often simpler) approach.
Some of the functionality that was previously only available with metaclasses is now available in a simpler form using class decorators. It is still useful, however, to understand metaclasses, and certain results can still be achieved only through metaclass programming.
Basic Metaprogramming
So metaclasses create classes, and classes create instances. Normally when we write a class, the default metaclass type is automatically invoked to create that class, and we aren't even aware that it's happening.
It's possible to explicitly code the metaclass' creation of a class. type called with one argument produces the type information of an existing class; type called with three arguments creates a new class object. The arguments when invoking type are the name of the class, a list of base classes, and a dictionary giving the namespace for the class (all the fields and methods). So the equivalent of:
class C: pass
is:
C = type('C', (), {})
Classes are often referred to as "types," so this reads fairly sensibly: you're calling a function that creates a new type based on its arguments.
We can also add base classes, fields and methods:
# Metaprogramming/MyList.py
def howdy(self, you):
print("Howdy, " + you)
MyList = type('MyList', (list,), dict(x=42, howdy=howdy))
ml = MyList()
ml.append("Camembert")
print(ml)
print(ml.x)
ml.howdy("John")
print(ml.__class__.__class__)
""" Output:
['Camembert']
42
Howdy, John
"""
Note that printing the class of the class produces the metaclass.
The ability to generate classes programmatically using type opens up some interesting possibilities. Consider the GreenHouseLanguage.py example in the Jython chapter ? all the subclasses in that case were written using repetetive code. We can automate the generation of the subclasses using type:
# Metaprogramming/GreenHouse.py
class Event(object):
events = [] # static
def __init__(self, action, time):
self.action = action
self.time = time
Event.events.append(self)
def __cmp__ (self, other):
"So sort() will compare only on time."
return cmp(self.time, other.time)
def run(self):
print("%.2f: %s" % (self.time, self.action))
@staticmethod
def run_events():
Event.events.sort();
for e in Event.events:
e.run()
def create_mc(description):
"Create subclass using the 'type' metaclass"
class_name = "".join(x.capitalize() for x in description.split())
def __init__(self, time):
Event.__init__(self, description + " [mc]", time)
globals()[class_name] = \
type(class_name, (Event,), dict(__init__ = __init__))
def create_exec(description):
"Create subclass by exec-ing a string"
class_name = "".join(x.capitalize() for x in description.split())
klass = """
class %s(Event):
def __init__(self, time):
Event.__init__(self, "%s [exec]", time)
""" % (class_name, description)
exec klass in globals()
if __name__ == "__main__":
descriptions = ["Light on", "Light off", "Water on", "Water off",
"Thermostat night", "Thermostat day", "Ring bell"]
initializations = "ThermostatNight(5.00); LightOff(2.00); \
WaterOn(3.30); WaterOff(4.45); LightOn(1.00); \
RingBell(7.00); ThermostatDay(6.00)"
[create_mc(dsc) for dsc in descriptions]
exec initializations in globals()
[create_exec(dsc) for dsc in descriptions]
exec initializations in globals()
Event.run_events()
""" Output:
1.00: Light on [mc]
1.00: Light on [exec]
2.00: Light off [mc]
2.00: Light off [exec]
3.30: Water on [mc]
3.30: Water on [exec]
4.45: Water off [mc]
4.45: Water off [exec]
5.00: Thermostat night [mc]
5.00: Thermostat night [exec]
6.00: Thermostat day [mc]
6.00: Thermostat day [exec]
7.00: Ring bell [mc]
7.00: Ring bell [exec]
"""
The Event base class is the same. The classes are created automatically using the create_mc() function, which takes its description argument and generates a class name from it. Then it defines an __init__() method, which it puts into the namespace dictionary for the type call, producing a new subclass of Event. Note that the resulting class must be inserted into the global namespace, otherwise it will not be seen.
This approach works fine, but then consider the subsequent create_exec() function, which accomplishes the same thing by calling exec on a string defining the class. This will be much easier to understand by the vast majority of the people reading your code: those who do not understand metaclasses.
The Metaclass Hook
So far, we've only used the type metaclass directly. Metaclass programming involves hooking our own operations into the creation of class objects. This is accomplished by:
Writing a subclass of the metaclass type.
Inserting the new metaclass into the class creation process using the metaclass hook.
In Python 2.x, the metaclass hook is a static field in the class called __metaclass__. In the ordinary case, this is not assigned so Python just uses type to create the class. But if you define __metaclass__ to point to a callable, Python will call __metaclass__() after the initial creation of the class object, passing in the class object, the class name, the list of base classes and the namespace dictionary.
Python 2.x also allows you to assign to the global __metaclass__ hook, which will be used if there is not a class-local __metaclass__ hook (is there an equivalent in Python 3?).
Thus, the basic process of metaclass programming looks like this:
# Metaprogramming/SimpleMeta1.py
# Two-step metaclass creation in Python 2.x
class SimpleMeta1(type):
def __init__(cls, name, bases, nmspc):
super(SimpleMeta1, cls).__init__(name, bases, nmspc)
cls.uses_metaclass = lambda self : "Yes!"
class Simple1(object):
__metaclass__ = SimpleMeta1
def foo(self): pass
@staticmethod
def bar(): pass
simple = Simple1()
print([m for m in dir(simple) if not m.startswith('__')])
# A new method has been injected by the metaclass:
print simple.uses_metaclass()
""" Output:
['bar', 'foo', 'uses_metaclass']
Yes!
"""
By convention, when defining metaclasses cls is used rather than self as the first argument to all methods except __new__() (which uses mcl, for reasons explained later). cls is the class object that is being modified.
Note that the practice of calling the base-class constructor first (via super()) in the derived-class constructor should be followed with metaclasses as well.
__metaclass__ only needs to be callable, so in Python 2.x it's possible to define __metaclass__ inline:
# Metaprogramming/SimpleMeta2.py
# Combining the steps for metaclass creation in Python 2.x
class Simple2(object):
class __metaclass__(type):
def __init__(cls, name, bases, nmspc):
# This won't work:
# super(__metaclass__, cls).__init__(name, bases, nmspc)
# Less-flexible specific call:
type.__init__(cls, name, bases, nmspc)
cls.uses_metaclass = lambda self : "Yes!"
class Simple3(Simple2): pass
simple = Simple3()
print simple.uses_metaclass()
""" Output:
Yes!
"""
The compiler won't accept the super() call because it says __metaclass__ hasn't been defined, forcing us to use the specific call to type.__init__().
Because it only needs to be callable, it's even possible to define __metaclass__ as a function:
# Metaprogramming/SimpleMeta3.py
# A function for __metaclass__ in Python 2.x
class Simple4(object):
def __metaclass__(name, bases, nmspc):
cls = type(name, bases, nmspc)
cls.uses_metaclass = lambda self : "Yes!"
return cls
simple = Simple4()
print simple.uses_metaclass()
""" Output:
Yes!
"""
As you'll see, Python 3 doesn't allow the syntax of these last two examples. Even so, the above example makes it quite clear what's happening: the class object is created, then modified, then returned.
Note
Or does it allow that syntax?
The Metaclass Hook in Python 3
Python 3 changes the metaclass hook. It doesn't disallow the __metaclass__ field, but it ignores it. Instead, you use a keyword argument in the base-class list:
class Simple1(object, metaclass = SimpleMeta1):
...
This means that none of the (clever) alternative ways of defining __metaclass__ directly as a class or function are available in Python 3 [[check this]]. All metaclasses must be defined as separate classes. This is probably just as well, as it makes metaclass programs more consistent and thus easier to read and understand.
Example: Self-Registration of Subclasses
It is sometimes convienient to use inheritance as an organizing mechanism ? each sublclass becomes an element of a group that you work on. For example, in CodeManager.py in the Comprehensions chapter, the subclasses of Language were all the languages that needed to be processed. Each Language subclass described specific processing traits for that language.
To solve this problem, consider a system that automatically keeps a list of all of its "leaf" subclasses (only the classes that have no inheritors). This way we can easily enumerate through all the subtypes:
# Metaprogramming/RegisterLeafClasses.py
class RegisterLeafClasses(type):
def __init__(cls, name, bases, nmspc):
super(RegisterLeafClasses, cls).__init__(name, bases, nmspc)
if not hasattr(cls, 'registry'):
cls.registry = set()
cls.registry.add(cls)
cls.registry -= set(bases) # Remove base classes
# Metamethods, called on class objects:
def __iter__(cls):
return iter(cls.registry)
def __str__(cls):
if cls in cls.registry:
return cls.__name__
return cls.__name__ + ": " + ", ".join([sc.__name__ for sc in cls])
class Color(object):
__metaclass__ = RegisterLeafClasses
class Blue(Color): pass
class Red(Color): pass
class Green(Color): pass
class Yellow(Color): pass
print(Color)
class PhthaloBlue(Blue): pass
class CeruleanBlue(Blue): pass
print(Color)
for c in Color: # Iterate over subclasses
print(c)
class Shape(object):
__metaclass__ = RegisterLeafClasses
class Round(Shape): pass
class Square(Shape): pass
class Triangular(Shape): pass
class Boxy(Shape): pass
print(Shape)
class Circle(Round): pass
class Ellipse(Round): pass
print(Shape)
""" Output:
Color: Red, Blue, Green, Yellow
Color: Red, CeruleanBlue, Green, PhthaloBlue, Yellow
Red
CeruleanBlue
Green
PhthaloBlue
Yellow
Shape: Square, Round, Boxy, Triangular
Shape: Square, Ellipse, Circle, Boxy, Triangular
"""
Two separate tests are used to show that the registries are independent of each other. Each test shows what happens when another level of leaf classes are added ? the former leaf becomes a base class, and so is removed from the registry.
This also introduces metamethods, which are defined in the metaclass so that they become methods of the class. That is, you call them on the class rather than object instances, and their first argument is the class object rather than self.
Using Class Decorators
Using the inspect module
(As in the Comprehensions chapter)
Example: Making a Class "Final"
It is sometimes convenient to prevent a class from being inherited:
# Metaprogramming/Final.py
# Emulating Java's 'final'
class final(type):
def __init__(cls, name, bases, namespace):
super(final, cls).__init__(name, bases, namespace)
for klass in bases:
if isinstance(klass, final):
raise TypeError(str(klass.__name__) + " is final")
class A(object):
pass
class B(A):
__metaclass__= final
print B.__bases__
print isinstance(B, final)
# Produces compile-time error:
class C(B):
pass
""" Output:
(<class '__main__.A'>,)
True
...
TypeError: B is final
"""
During class object creation, we check to see if any of the bases are derived from final. Notice that using a metaclass makes the new type an instance of that metaclass, even though the metaclass doesn't show up in the base-class list.
Because this process of checking for finality must be installed to happen as the subclasses are created, rather than afterwards as performed by class decorators, it appears that this is an example of something that requires metaclasses and can't be accomplished with class decorators.
Using __init__ vs. __new__ in Metaclasses
It can be confusing when you see metaclass examples that appear to arbitrarily use __new__ or __init__ ? why choose one over the other?
__new__ is called for the creation of a new class, while __init__ is called after the class is created, to perform additional initialization before the class is handed to the caller:
# Metaprogramming/NewVSInit.py
from pprint import pprint
class Tag1: pass
class Tag2: pass
class Tag3:
def tag3_method(self): pass
class MetaBase(type):
def __new__(mcl, name, bases, nmspc):
print('MetaBase.__new__\n')
return super(MetaBase, mcl).__new__(mcl, name, bases, nmspc)
def __init__(cls, name, bases, nmspc):
print('MetaBase.__init__\n')
super(MetaBase, cls).__init__(name, bases, nmspc)
class MetaNewVSInit(MetaBase):
def __new__(mcl, name, bases, nmspc):
# First argument is the metaclass ``MetaNewVSInit``
print('MetaNewVSInit.__new__')
for x in (mcl, name, bases, nmspc): pprint(x)
print('')
# These all work because the class hasn't been created yet:
if 'foo' in nmspc: nmspc.pop('foo')
name += '_x'
bases += (Tag1,)
nmspc['baz'] = 42
return super(MetaNewVSInit, mcl).__new__(mcl, name, bases, nmspc)
def __init__(cls, name, bases, nmspc):
# First argument is the class being initialized
print('MetaNewVSInit.__init__')
for x in (cls, name, bases, nmspc): pprint(x)
print('')
if 'bar' in nmspc: nmspc.pop('bar') # No effect
name += '_y' # No effect
bases += (Tag2,) # No effect
nmspc['pi'] = 3.14159 # No effect
super(MetaNewVSInit, cls).__init__(name, bases, nmspc)
# These do work because they operate on the class object:
cls.__name__ += '_z'
cls.__bases__ += (Tag3,)
cls.e = 2.718
class Test(object):
__metaclass__ = MetaNewVSInit
def __init__(self):
print('Test.__init__')
def foo(self): print('foo still here')
def bar(self): print('bar still here')
t = Test()
print('class name: ' + Test.__name__)
print('base classes: ', [c.__name__ for c in Test.__bases__])
print([m for m in dir(t) if not m.startswith("__")])
t.bar()
print(t.e)
""" Output:
MetaNewVSInit.__new__
<class '__main__.MetaNewVSInit'>
'Test'
(<type 'object'>,)
{'__init__': <function __init__ at 0x7ecf0>,
'__metaclass__': <class '__main__.MetaNewVSInit'>,
'__module__': '__main__',
'bar': <function bar at 0x7ed70>,
'foo': <function foo at 0x7ed30>}
MetaBase.__new__
MetaNewVSInit.__init__
<class '__main__.Test_x'>
'Test'
(<type 'object'>,)
{'__init__': <function __init__ at 0x7ecf0>,
'__metaclass__': <class '__main__.MetaNewVSInit'>,
'__module__': '__main__',
'bar': <function bar at 0x7ed70>,
'baz': 42}
MetaBase.__init__
Test.__init__
class name: Test_x_z
('base classes: ', ['object', 'Tag1', 'Tag3'])
['bar', 'baz', 'e', 'tag3_method']
bar still here
2.718
"""
The primary difference is that when overriding __new__() you can change things like the 'name', 'bases' and 'namespace' arguments before you call the super constructor and it will have an effect, but doing the same thing in __init__() you won't get any results from the constructor call.
One special case in __new__() is that you can manipulate things like __slots__, but in __init__() you can't.
Note that, since the base-class version of __init__() doesn't make any modifications, it makes sense to call it first, then perform any additional operations. In C++ and Java, the base-class constructor must be called as the first operation in a derived-class constructor, which makes sense because derived-class constructions can then build upon base-class foundations.
In many cases, the choice of __new__() vs __init__() is a style issue and doesn't matter, but because __new__() can do everything and __init__() is slightly more limited, some people just start using __new__() and stick with it. This use can be confusing ? I tend to hunt for the reason that __init__() has been chosen, and if I can't find it wonder whether the author knew what they were doing. I prefer to only use __new__() when it has meaning ? when you must in order to change things that only __new__() can change.
Class Methods and Metamethods
A metamethod can be called from either the metaclass or from the class, but not from an instance. A classmethod can be called from either a class or its instances, but is not part of the metaclass.
(Is a similar relationship true with attributes, or is it different?)
Intercepting Class Creation
This example implements Singleton using metaclasses, by overriding the __call__() metamethod, which is invoked when a new instance is created:
# Metaprogramming/Singleton.py
class Singleton(type):
instance = None
def __call__(cls, *args, **kw):
if not cls.instance:
cls.instance = super(Singleton, cls).__call__(*args, **kw)
return cls.instance
class ASingleton(object):
__metaclass__ = Singleton
a = ASingleton()
b = ASingleton()
assert a is b
print(a.__class__.__name__, b.__class__.__name__)
class BSingleton(object):
__metaclass__ = Singleton
c = BSingleton()
d = BSingleton()
assert c is d
print(c.__class__.__name__, d.__class__.__name__)
assert c is not a
""" Output:
('ASingleton', 'ASingleton')
('BSingleton', 'BSingleton')
"""
By overriding __call__() in the metaclass, the creation of instances are intercepted. Instance creation is bypassed if one already exists.
Note the dependence upon the behavior of static class fields. When cls.instance is first read, it gets the static value of instance from the metaclass, which is None. However, when the assignment is made, Python creates a local version for the particular class, and the next time cls.instance is read, it sees that local version. Because of this behavior, each class ends up with its own class-specific instance field (thus instance is not somehow being "inherited" from the metaclass).
A Class Decorator Singleton
# Metaprogramming/SingletonDecorator.py
def singleton(klass):
"Simple replacement of object creation operation"
def getinstance(*args, **kw):
if not hasattr(klass, 'instance'):
klass.instance = klass(*args, **kw)
return klass.instance
return getinstance
def singleton(klass):
"""
More powerful approach: Change the behavior
of the instances AND the class object.
"""
class Decorated(klass):
def __init__(self, *args, **kwargs):
if hasattr(klass, '__init__'):
klass.__init__(self, *args, **kwargs)
def __repr__(self) : return klass.__name__ + " obj"
__str__ = __repr__
Decorated.__name__ = klass.__name__
class ClassObject:
def __init__(cls):
cls.instance = None
def __repr__(cls):
return klass.__name__
__str__ = __repr__
def __call__(cls, *args, **kwargs):
print str(cls) + " __call__ "
if not cls.instance:
cls.instance = Decorated(*args, **kwargs)
return cls.instance
return ClassObject()
@singleton
class ASingleton: pass
a = ASingleton()
b = ASingleton()
print(a, b)
print a.__class__.__name__
print ASingleton
assert a is b
@singleton
class BSingleton:
def __init__(self, x):
self.x = x
c = BSingleton(11)
d = BSingleton(22)
assert c is d
assert c is not a
""" Output:
ASingleton __call__
ASingleton __call__
(ASingleton obj, ASingleton obj)
ASingleton
ASingleton
BSingleton __call__
BSingleton __call__
"""
The __prepare__() Metamethod
One of the things you can't do with class decorators is to replace the default dictionary. In Python 3 this is enabled with the __prepare__() metamethod:
@classmethod
def __prepare__(mcl, name, bases):
return odict()
For an example of using both __prepare__() and __slots__ in metaclasses, see Michele Simionato's article.
Module-level __metaclass__ Assignment
(Does this work in Python 3? If not is there an alternative?)
Metaclass Conflicts
Note that the metaclass argument is singular ? you can't attach more than one metaclass to a class. However, through multiple inheritance you can accidentally end up with more than one metaclass, and this produces a conflict which must be resolved.
http://code.activestate.com/recipes/204197/
Further Reading
Excellent step-by-step introduction to metaclasses:
http://cleverdevil.org/computing/78/
Metaclass intro and comparison of syntax between Python 2.x and 3.x:
http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/
David Mertz's metaclass primer:
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html
Three-part in-depth coverage of metaclasses on IBM Developer Works. Quite useful and authoritative:
http://www.ibm.com/developerworks/linux/library/l-pymeta.html
http://www.ibm.com/developerworks/linux/library/l-pymeta2/
http://www.ibm.com/developerworks/linux/library/l-pymeta3.html
Michele Simionato's articles on Artima, with special emphasis on the difference between Python 2.x and 3.x metaclasses:
http://www.artima.com/weblogs/viewpost.jsp?thread=236234
http://www.artima.com/weblogs/viewpost.jsp?thread=236260
Once you understand the foundations, you can find lots of examples by searching for "metaclass" within the Python Cookbook: http://code.activestate.com/recipes/langs/python/
The printed version of the Python Cookbook has far fewer examples than the online version, but the print version has been filtered and edited and so tends to be more authoritative.
Ian Bicking writes about metaclasses:
http://blog.ianbicking.org/a-conservative-metaclass.html
http://blog.ianbicking.org/metaclass-fun.html
http://blog.ianbicking.org/A-Declarative-Syntax-Extension.html
http://blog.ianbicking.org/self-take-two.html
Lots of good information about classes, types, metaclasses, etc., including historical stuff in the Python 2.2 docs (is this duplicated in later versions of the docs):
http://www.python.org/download/releases/2.2/descrintro/
Classes are just objects, and they can be modified the same way:
>>> class Foo: pass
...
>>> Foo.field = 42
>>> x = Foo()
>>> x.field
42
>>> Foo.field2 = 99
>>> x.field2
99
>>> Foo.method = lambda self: "Hi!"
>>> x.method()
'Hi!'
To modify a class, you perform operations on it like any other object. You can add and subtract fields and methods, for example. The difference is that any change you make to a class affects all the objects of that class, even the ones that have already been instantiated.
What creates these special "class" objects? Other special objects, called metaclasses.
The default metaclass is called type and in the vast majority of cases it does the right thing. In some situations, however, you can gain leverage by modifying the way that classes are produced ? typically by performing extra actions or injecting code. When this is the case, you can use metaclass programming to modify the way that some of your class objects are created.
It's worth re-emphasizing that in the vast majority of cases, you don't need metaclasses, because it's a fascinating toy and the temptation to use it everywhere can be overwhelming. Some of the examples in this chapter will show both metaclass and non-metaclass solutions to a problem, so you can see that there's usually another (often simpler) approach.
Some of the functionality that was previously only available with metaclasses is now available in a simpler form using class decorators. It is still useful, however, to understand metaclasses, and certain results can still be achieved only through metaclass programming.
Basic Metaprogramming
So metaclasses create classes, and classes create instances. Normally when we write a class, the default metaclass type is automatically invoked to create that class, and we aren't even aware that it's happening.
It's possible to explicitly code the metaclass' creation of a class. type called with one argument produces the type information of an existing class; type called with three arguments creates a new class object. The arguments when invoking type are the name of the class, a list of base classes, and a dictionary giving the namespace for the class (all the fields and methods). So the equivalent of:
class C: pass
is:
C = type('C', (), {})
Classes are often referred to as "types," so this reads fairly sensibly: you're calling a function that creates a new type based on its arguments.
We can also add base classes, fields and methods:
# Metaprogramming/MyList.py
def howdy(self, you):
print("Howdy, " + you)
MyList = type('MyList', (list,), dict(x=42, howdy=howdy))
ml = MyList()
ml.append("Camembert")
print(ml)
print(ml.x)
ml.howdy("John")
print(ml.__class__.__class__)
""" Output:
['Camembert']
42
Howdy, John
"""
Note that printing the class of the class produces the metaclass.
The ability to generate classes programmatically using type opens up some interesting possibilities. Consider the GreenHouseLanguage.py example in the Jython chapter ? all the subclasses in that case were written using repetetive code. We can automate the generation of the subclasses using type:
# Metaprogramming/GreenHouse.py
class Event(object):
events = [] # static
def __init__(self, action, time):
self.action = action
self.time = time
Event.events.append(self)
def __cmp__ (self, other):
"So sort() will compare only on time."
return cmp(self.time, other.time)
def run(self):
print("%.2f: %s" % (self.time, self.action))
@staticmethod
def run_events():
Event.events.sort();
for e in Event.events:
e.run()
def create_mc(description):
"Create subclass using the 'type' metaclass"
class_name = "".join(x.capitalize() for x in description.split())
def __init__(self, time):
Event.__init__(self, description + " [mc]", time)
globals()[class_name] = \
type(class_name, (Event,), dict(__init__ = __init__))
def create_exec(description):
"Create subclass by exec-ing a string"
class_name = "".join(x.capitalize() for x in description.split())
klass = """
class %s(Event):
def __init__(self, time):
Event.__init__(self, "%s [exec]", time)
""" % (class_name, description)
exec klass in globals()
if __name__ == "__main__":
descriptions = ["Light on", "Light off", "Water on", "Water off",
"Thermostat night", "Thermostat day", "Ring bell"]
initializations = "ThermostatNight(5.00); LightOff(2.00); \
WaterOn(3.30); WaterOff(4.45); LightOn(1.00); \
RingBell(7.00); ThermostatDay(6.00)"
[create_mc(dsc) for dsc in descriptions]
exec initializations in globals()
[create_exec(dsc) for dsc in descriptions]
exec initializations in globals()
Event.run_events()
""" Output:
1.00: Light on [mc]
1.00: Light on [exec]
2.00: Light off [mc]
2.00: Light off [exec]
3.30: Water on [mc]
3.30: Water on [exec]
4.45: Water off [mc]
4.45: Water off [exec]
5.00: Thermostat night [mc]
5.00: Thermostat night [exec]
6.00: Thermostat day [mc]
6.00: Thermostat day [exec]
7.00: Ring bell [mc]
7.00: Ring bell [exec]
"""
The Event base class is the same. The classes are created automatically using the create_mc() function, which takes its description argument and generates a class name from it. Then it defines an __init__() method, which it puts into the namespace dictionary for the type call, producing a new subclass of Event. Note that the resulting class must be inserted into the global namespace, otherwise it will not be seen.
This approach works fine, but then consider the subsequent create_exec() function, which accomplishes the same thing by calling exec on a string defining the class. This will be much easier to understand by the vast majority of the people reading your code: those who do not understand metaclasses.
The Metaclass Hook
So far, we've only used the type metaclass directly. Metaclass programming involves hooking our own operations into the creation of class objects. This is accomplished by:
Writing a subclass of the metaclass type.
Inserting the new metaclass into the class creation process using the metaclass hook.
In Python 2.x, the metaclass hook is a static field in the class called __metaclass__. In the ordinary case, this is not assigned so Python just uses type to create the class. But if you define __metaclass__ to point to a callable, Python will call __metaclass__() after the initial creation of the class object, passing in the class object, the class name, the list of base classes and the namespace dictionary.
Python 2.x also allows you to assign to the global __metaclass__ hook, which will be used if there is not a class-local __metaclass__ hook (is there an equivalent in Python 3?).
Thus, the basic process of metaclass programming looks like this:
# Metaprogramming/SimpleMeta1.py
# Two-step metaclass creation in Python 2.x
class SimpleMeta1(type):
def __init__(cls, name, bases, nmspc):
super(SimpleMeta1, cls).__init__(name, bases, nmspc)
cls.uses_metaclass = lambda self : "Yes!"
class Simple1(object):
__metaclass__ = SimpleMeta1
def foo(self): pass
@staticmethod
def bar(): pass
simple = Simple1()
print([m for m in dir(simple) if not m.startswith('__')])
# A new method has been injected by the metaclass:
print simple.uses_metaclass()
""" Output:
['bar', 'foo', 'uses_metaclass']
Yes!
"""
By convention, when defining metaclasses cls is used rather than self as the first argument to all methods except __new__() (which uses mcl, for reasons explained later). cls is the class object that is being modified.
Note that the practice of calling the base-class constructor first (via super()) in the derived-class constructor should be followed with metaclasses as well.
__metaclass__ only needs to be callable, so in Python 2.x it's possible to define __metaclass__ inline:
# Metaprogramming/SimpleMeta2.py
# Combining the steps for metaclass creation in Python 2.x
class Simple2(object):
class __metaclass__(type):
def __init__(cls, name, bases, nmspc):
# This won't work:
# super(__metaclass__, cls).__init__(name, bases, nmspc)
# Less-flexible specific call:
type.__init__(cls, name, bases, nmspc)
cls.uses_metaclass = lambda self : "Yes!"
class Simple3(Simple2): pass
simple = Simple3()
print simple.uses_metaclass()
""" Output:
Yes!
"""
The compiler won't accept the super() call because it says __metaclass__ hasn't been defined, forcing us to use the specific call to type.__init__().
Because it only needs to be callable, it's even possible to define __metaclass__ as a function:
# Metaprogramming/SimpleMeta3.py
# A function for __metaclass__ in Python 2.x
class Simple4(object):
def __metaclass__(name, bases, nmspc):
cls = type(name, bases, nmspc)
cls.uses_metaclass = lambda self : "Yes!"
return cls
simple = Simple4()
print simple.uses_metaclass()
""" Output:
Yes!
"""
As you'll see, Python 3 doesn't allow the syntax of these last two examples. Even so, the above example makes it quite clear what's happening: the class object is created, then modified, then returned.
Note
Or does it allow that syntax?
The Metaclass Hook in Python 3
Python 3 changes the metaclass hook. It doesn't disallow the __metaclass__ field, but it ignores it. Instead, you use a keyword argument in the base-class list:
class Simple1(object, metaclass = SimpleMeta1):
...
This means that none of the (clever) alternative ways of defining __metaclass__ directly as a class or function are available in Python 3 [[check this]]. All metaclasses must be defined as separate classes. This is probably just as well, as it makes metaclass programs more consistent and thus easier to read and understand.
Example: Self-Registration of Subclasses
It is sometimes convienient to use inheritance as an organizing mechanism ? each sublclass becomes an element of a group that you work on. For example, in CodeManager.py in the Comprehensions chapter, the subclasses of Language were all the languages that needed to be processed. Each Language subclass described specific processing traits for that language.
To solve this problem, consider a system that automatically keeps a list of all of its "leaf" subclasses (only the classes that have no inheritors). This way we can easily enumerate through all the subtypes:
# Metaprogramming/RegisterLeafClasses.py
class RegisterLeafClasses(type):
def __init__(cls, name, bases, nmspc):
super(RegisterLeafClasses, cls).__init__(name, bases, nmspc)
if not hasattr(cls, 'registry'):
cls.registry = set()
cls.registry.add(cls)
cls.registry -= set(bases) # Remove base classes
# Metamethods, called on class objects:
def __iter__(cls):
return iter(cls.registry)
def __str__(cls):
if cls in cls.registry:
return cls.__name__
return cls.__name__ + ": " + ", ".join([sc.__name__ for sc in cls])
class Color(object):
__metaclass__ = RegisterLeafClasses
class Blue(Color): pass
class Red(Color): pass
class Green(Color): pass
class Yellow(Color): pass
print(Color)
class PhthaloBlue(Blue): pass
class CeruleanBlue(Blue): pass
print(Color)
for c in Color: # Iterate over subclasses
print(c)
class Shape(object):
__metaclass__ = RegisterLeafClasses
class Round(Shape): pass
class Square(Shape): pass
class Triangular(Shape): pass
class Boxy(Shape): pass
print(Shape)
class Circle(Round): pass
class Ellipse(Round): pass
print(Shape)
""" Output:
Color: Red, Blue, Green, Yellow
Color: Red, CeruleanBlue, Green, PhthaloBlue, Yellow
Red
CeruleanBlue
Green
PhthaloBlue
Yellow
Shape: Square, Round, Boxy, Triangular
Shape: Square, Ellipse, Circle, Boxy, Triangular
"""
Two separate tests are used to show that the registries are independent of each other. Each test shows what happens when another level of leaf classes are added ? the former leaf becomes a base class, and so is removed from the registry.
This also introduces metamethods, which are defined in the metaclass so that they become methods of the class. That is, you call them on the class rather than object instances, and their first argument is the class object rather than self.
Using Class Decorators
Using the inspect module
(As in the Comprehensions chapter)
Example: Making a Class "Final"
It is sometimes convenient to prevent a class from being inherited:
# Metaprogramming/Final.py
# Emulating Java's 'final'
class final(type):
def __init__(cls, name, bases, namespace):
super(final, cls).__init__(name, bases, namespace)
for klass in bases:
if isinstance(klass, final):
raise TypeError(str(klass.__name__) + " is final")
class A(object):
pass
class B(A):
__metaclass__= final
print B.__bases__
print isinstance(B, final)
# Produces compile-time error:
class C(B):
pass
""" Output:
(<class '__main__.A'>,)
True
...
TypeError: B is final
"""
During class object creation, we check to see if any of the bases are derived from final. Notice that using a metaclass makes the new type an instance of that metaclass, even though the metaclass doesn't show up in the base-class list.
Because this process of checking for finality must be installed to happen as the subclasses are created, rather than afterwards as performed by class decorators, it appears that this is an example of something that requires metaclasses and can't be accomplished with class decorators.
Using __init__ vs. __new__ in Metaclasses
It can be confusing when you see metaclass examples that appear to arbitrarily use __new__ or __init__ ? why choose one over the other?
__new__ is called for the creation of a new class, while __init__ is called after the class is created, to perform additional initialization before the class is handed to the caller:
# Metaprogramming/NewVSInit.py
from pprint import pprint
class Tag1: pass
class Tag2: pass
class Tag3:
def tag3_method(self): pass
class MetaBase(type):
def __new__(mcl, name, bases, nmspc):
print('MetaBase.__new__\n')
return super(MetaBase, mcl).__new__(mcl, name, bases, nmspc)
def __init__(cls, name, bases, nmspc):
print('MetaBase.__init__\n')
super(MetaBase, cls).__init__(name, bases, nmspc)
class MetaNewVSInit(MetaBase):
def __new__(mcl, name, bases, nmspc):
# First argument is the metaclass ``MetaNewVSInit``
print('MetaNewVSInit.__new__')
for x in (mcl, name, bases, nmspc): pprint(x)
print('')
# These all work because the class hasn't been created yet:
if 'foo' in nmspc: nmspc.pop('foo')
name += '_x'
bases += (Tag1,)
nmspc['baz'] = 42
return super(MetaNewVSInit, mcl).__new__(mcl, name, bases, nmspc)
def __init__(cls, name, bases, nmspc):
# First argument is the class being initialized
print('MetaNewVSInit.__init__')
for x in (cls, name, bases, nmspc): pprint(x)
print('')
if 'bar' in nmspc: nmspc.pop('bar') # No effect
name += '_y' # No effect
bases += (Tag2,) # No effect
nmspc['pi'] = 3.14159 # No effect
super(MetaNewVSInit, cls).__init__(name, bases, nmspc)
# These do work because they operate on the class object:
cls.__name__ += '_z'
cls.__bases__ += (Tag3,)
cls.e = 2.718
class Test(object):
__metaclass__ = MetaNewVSInit
def __init__(self):
print('Test.__init__')
def foo(self): print('foo still here')
def bar(self): print('bar still here')
t = Test()
print('class name: ' + Test.__name__)
print('base classes: ', [c.__name__ for c in Test.__bases__])
print([m for m in dir(t) if not m.startswith("__")])
t.bar()
print(t.e)
""" Output:
MetaNewVSInit.__new__
<class '__main__.MetaNewVSInit'>
'Test'
(<type 'object'>,)
{'__init__': <function __init__ at 0x7ecf0>,
'__metaclass__': <class '__main__.MetaNewVSInit'>,
'__module__': '__main__',
'bar': <function bar at 0x7ed70>,
'foo': <function foo at 0x7ed30>}
MetaBase.__new__
MetaNewVSInit.__init__
<class '__main__.Test_x'>
'Test'
(<type 'object'>,)
{'__init__': <function __init__ at 0x7ecf0>,
'__metaclass__': <class '__main__.MetaNewVSInit'>,
'__module__': '__main__',
'bar': <function bar at 0x7ed70>,
'baz': 42}
MetaBase.__init__
Test.__init__
class name: Test_x_z
('base classes: ', ['object', 'Tag1', 'Tag3'])
['bar', 'baz', 'e', 'tag3_method']
bar still here
2.718
"""
The primary difference is that when overriding __new__() you can change things like the 'name', 'bases' and 'namespace' arguments before you call the super constructor and it will have an effect, but doing the same thing in __init__() you won't get any results from the constructor call.
One special case in __new__() is that you can manipulate things like __slots__, but in __init__() you can't.
Note that, since the base-class version of __init__() doesn't make any modifications, it makes sense to call it first, then perform any additional operations. In C++ and Java, the base-class constructor must be called as the first operation in a derived-class constructor, which makes sense because derived-class constructions can then build upon base-class foundations.
In many cases, the choice of __new__() vs __init__() is a style issue and doesn't matter, but because __new__() can do everything and __init__() is slightly more limited, some people just start using __new__() and stick with it. This use can be confusing ? I tend to hunt for the reason that __init__() has been chosen, and if I can't find it wonder whether the author knew what they were doing. I prefer to only use __new__() when it has meaning ? when you must in order to change things that only __new__() can change.
Class Methods and Metamethods
A metamethod can be called from either the metaclass or from the class, but not from an instance. A classmethod can be called from either a class or its instances, but is not part of the metaclass.
(Is a similar relationship true with attributes, or is it different?)
Intercepting Class Creation
This example implements Singleton using metaclasses, by overriding the __call__() metamethod, which is invoked when a new instance is created:
# Metaprogramming/Singleton.py
class Singleton(type):
instance = None
def __call__(cls, *args, **kw):
if not cls.instance:
cls.instance = super(Singleton, cls).__call__(*args, **kw)
return cls.instance
class ASingleton(object):
__metaclass__ = Singleton
a = ASingleton()
b = ASingleton()
assert a is b
print(a.__class__.__name__, b.__class__.__name__)
class BSingleton(object):
__metaclass__ = Singleton
c = BSingleton()
d = BSingleton()
assert c is d
print(c.__class__.__name__, d.__class__.__name__)
assert c is not a
""" Output:
('ASingleton', 'ASingleton')
('BSingleton', 'BSingleton')
"""
By overriding __call__() in the metaclass, the creation of instances are intercepted. Instance creation is bypassed if one already exists.
Note the dependence upon the behavior of static class fields. When cls.instance is first read, it gets the static value of instance from the metaclass, which is None. However, when the assignment is made, Python creates a local version for the particular class, and the next time cls.instance is read, it sees that local version. Because of this behavior, each class ends up with its own class-specific instance field (thus instance is not somehow being "inherited" from the metaclass).
A Class Decorator Singleton
# Metaprogramming/SingletonDecorator.py
def singleton(klass):
"Simple replacement of object creation operation"
def getinstance(*args, **kw):
if not hasattr(klass, 'instance'):
klass.instance = klass(*args, **kw)
return klass.instance
return getinstance
def singleton(klass):
"""
More powerful approach: Change the behavior
of the instances AND the class object.
"""
class Decorated(klass):
def __init__(self, *args, **kwargs):
if hasattr(klass, '__init__'):
klass.__init__(self, *args, **kwargs)
def __repr__(self) : return klass.__name__ + " obj"
__str__ = __repr__
Decorated.__name__ = klass.__name__
class ClassObject:
def __init__(cls):
cls.instance = None
def __repr__(cls):
return klass.__name__
__str__ = __repr__
def __call__(cls, *args, **kwargs):
print str(cls) + " __call__ "
if not cls.instance:
cls.instance = Decorated(*args, **kwargs)
return cls.instance
return ClassObject()
@singleton
class ASingleton: pass
a = ASingleton()
b = ASingleton()
print(a, b)
print a.__class__.__name__
print ASingleton
assert a is b
@singleton
class BSingleton:
def __init__(self, x):
self.x = x
c = BSingleton(11)
d = BSingleton(22)
assert c is d
assert c is not a
""" Output:
ASingleton __call__
ASingleton __call__
(ASingleton obj, ASingleton obj)
ASingleton
ASingleton
BSingleton __call__
BSingleton __call__
"""
The __prepare__() Metamethod
One of the things you can't do with class decorators is to replace the default dictionary. In Python 3 this is enabled with the __prepare__() metamethod:
@classmethod
def __prepare__(mcl, name, bases):
return odict()
For an example of using both __prepare__() and __slots__ in metaclasses, see Michele Simionato's article.
Module-level __metaclass__ Assignment
(Does this work in Python 3? If not is there an alternative?)
Metaclass Conflicts
Note that the metaclass argument is singular ? you can't attach more than one metaclass to a class. However, through multiple inheritance you can accidentally end up with more than one metaclass, and this produces a conflict which must be resolved.
http://code.activestate.com/recipes/204197/
Further Reading
Excellent step-by-step introduction to metaclasses:
http://cleverdevil.org/computing/78/
Metaclass intro and comparison of syntax between Python 2.x and 3.x:
http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/
David Mertz's metaclass primer:
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html
Three-part in-depth coverage of metaclasses on IBM Developer Works. Quite useful and authoritative:
http://www.ibm.com/developerworks/linux/library/l-pymeta.html
http://www.ibm.com/developerworks/linux/library/l-pymeta2/
http://www.ibm.com/developerworks/linux/library/l-pymeta3.html
Michele Simionato's articles on Artima, with special emphasis on the difference between Python 2.x and 3.x metaclasses:
http://www.artima.com/weblogs/viewpost.jsp?thread=236234
http://www.artima.com/weblogs/viewpost.jsp?thread=236260
Once you understand the foundations, you can find lots of examples by searching for "metaclass" within the Python Cookbook: http://code.activestate.com/recipes/langs/python/
The printed version of the Python Cookbook has far fewer examples than the online version, but the print version has been filtered and edited and so tends to be more authoritative.
Ian Bicking writes about metaclasses:
http://blog.ianbicking.org/a-conservative-metaclass.html
http://blog.ianbicking.org/metaclass-fun.html
http://blog.ianbicking.org/A-Declarative-Syntax-Extension.html
http://blog.ianbicking.org/self-take-two.html
Lots of good information about classes, types, metaclasses, etc., including historical stuff in the Python 2.2 docs (is this duplicated in later versions of the docs):
http://www.python.org/download/releases/2.2/descrintro/
How Metaclasses work technically in Python 2 and 3
A metaclass is a class/object which defines a type/class of other classes. In Python a metaclass can be a class, function or any object that supports calling an interface. This is because to create a class object; its metaclass is called with the class name, base classes and attributes (methods). When no metaclass is defined (which is usually the case), the default metaclass type is used.
For example:
Python 3.x
# Here __metaclass__ points to the metaclass object.
class ExampleClass(metaclass=type):
pass
Python 2.x
# Here __metaclass__ points to the metaclass object.
class ExampleClass(object):
__metaclass__ = type
pass
When a class is created, the interpreter:
Gets the name of the class.
Gets the base classes of the class.
Gets the metaclass of the class. If it is defined, it will use this first. Otherwise, it will check in the base classes for the metaclass. It it can't find a metaclass in the base class, the type object is used instead.
Gets the variables/attributes in the class and stores them as a dictionary.
Passes this information to metaclass as metaclass(name_of_class, base_classes, attributes_dictionary) and it returns a class object.
For example:
# type(name, base, attrs)
# name is the name of the class
# base is a tuple of base classes (all methods/attributes are inherited
# from these) attrs is a dictionary filled with the class attributes
classObject = type('ExampleClass', (object,) ,{})
When type is called, its __call__ method is called. This method in turn calls the __new__ and __init__ methods. The __new__ method creates a new object, whereas the __init__ method initializes it. We can easily play with methods. This is a working example:
Python 3.x
class a:
def __init__(self, data):
self.data = data
def getd3(self):
return self.data * 3
class MyMeta(type):
def __new__(metaname, classname, baseclasses, attrs):
print('New called with')
print('metaname', metaname)
print('classname', classname)
print('baseclasses', baseclasses)
print('attrs', attrs)
attrs['getdata'] = a.__dict__['getd3']
# attrs['getdata'] = a.getd3
return type.__new__(metaname, classname, baseclasses, attrs)
def __init__(classobject, classname, baseclasses, attrs):
print('init called with')
print('classobject', classobject)
print('classname', classname)
print('baseclasses', baseclasses)
print('attrs', attrs)
class Kls(metaclass=MyMeta):
def __init__(self,data):
self.data = data
def printd(self):
print(self.data)
ik = Kls('arun')
ik.printd()
print(ik.getdata())
When running the code, we get:
New called with
metaname <class '__main__.MyMeta'>
classname Kls
baseclasses ()
attrs {'__module__': '__main__', 'printd': <function printd at 0x7f3ebca86958>, '__init__': <function __init__ at 0x7f3ebca868d0>}
init called with
classobject <class '__main__.Kls'>
classname Kls
baseclasses ()
attrs {'__module__': '__main__', 'getdata': <function getd3 at 0x7f3ebca86408>, 'printd': <function printd at 0x7f3ebca86958>, '__init__': <function __init__ at 0x7f3ebca868d0>}
arun
arunarunarun
Python 2.x
class a(object):
def __init__(self, data):
self.data = data
def getd3(self):
return self.data * 3
class MyMeta(type):
def __new__(metaname, classname, baseclasses, attrs):
print 'New called with'
print 'metaname', metaname
print 'classname', classname
print 'baseclasses', baseclasses
print 'attrs', attrs
attrs['getdata'] = a.__dict__['getd3']
# attrs['getdata'] = a.getd3
return type.__new__(metaname, classname, baseclasses, attrs)
def __init__(classobject, classname, baseclasses, attrs):
print 'init called with'
print 'classobject', classobject
print 'classname', classname
print 'baseclasses', baseclasses
print 'attrs', attrs
class Kls(object):
__metaclass__ = MyMeta
def __init__(self, data):
self.data = data
def printd(self):
print self.data
ik = Kls('arun')
ik.printd()
print ik.getdata()
When running the code, we get:
New called with
metaname <class '__main__.MyMeta'>
classname Kls
baseclasses (<type 'object'>,)
attrs {'__module__': '__main__', '__metaclass__': <class '__main__.MyMeta'>, 'printd': <function printd at 0x7fbdab0176e0>, '__init__': <function __init__ at 0x7fbdab017668>}
init called with
classobject <class '__main__.Kls'>
classname Kls
baseclasses (<type 'object'>,)
attrs {'__module__': '__main__', 'getdata': <function getd3 at 0x7fbdab017500>, '__metaclass__': <class '__main__.MyMeta'>, 'printd': <function printd at 0x7fbdab0176e0>, '__init__': <function __init__ at 0x7fbdab017668>}
arun
arunarunarun
Normally we need to override only one method __new__ or __init__. We can also use function instead of a class. Here is an example:
Python 3.x
def meta_func(name, bases, attrs):
print('meta function called with', name, bases, attrs)
nattrs = {'mod' + key:attrs[key] for key in attrs}
return type(name, bases, nattrs)
MyMeta = meta_func
class Kls(metaclass=MyMeta):
def setd(self, data):
self.data = data
def getd(self):
return self.data
k = Kls()
k.modsetd('arun')
print(k.modgetd())
Gives us the following output:
meta function called with Kls () {'setd': <function setd at 0x7f3bafe7cd10>, '__module__': '__main__', 'getd': <function getd at 0x7f3bafe7cd98>}
arun
Python 2.x
def meta_func(name, bases, attrs):
print 'meta function called with', name, bases, attrs
nattrs = {'mod' + key:attrs[key] for key in attrs}
return type(name, bases, nattrs)
MyMeta = meta_func
class Kls(object):
__metaclass__ = MyMeta
def setd(self, data):
self.data = data
def getd(self):
return self.data
k = Kls()
k.modsetd('arun')
print k.modgetd()
Gives us the following output:
meta function called with Kls (<type 'object'>,) {'setd': <function setd at 0x88b21ec>, 'getd': <function getd at 0x88b22cc>, '__module__': '__main__', '__metaclass__': <function meta_func at 0xb72341b4>}
arun
Other then modifying base classes and methods of classes to be created, metaclasses can also modify instance creation process. This is because when we create an instance (ik = Kls()), this is like calling the class Kls. One point to note is that whenever we call an object its type's __call__ method is called. So in this case the class type is metaclass hence its __call__ method will be called. We can check like this:
Python 3.x
class MyMeta(type):
def __call__(clsname, *args):
print('MyMeta called with')
print('clsname:', clsname)
print('args:', args)
instance = object.__new__(clsname)
instance.__init__(*args)
return instance
class Kls(metaclass=MyMeta):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
ik = Kls('arun')
ik.printd()
Python 2.x
class MyMeta(type):
def __call__(clsname, *args):
print 'MyMeta called with'
print 'clsname:', clsname
print 'args:' ,args
instance = object.__new__(clsname)
instance.__init__(*args)
return instance
class Kls(object):
__metaclass__ = MyMeta
def __init__(self,data):
self.data = data
def printd(self):
print self.data
ik = Kls('arun')
ik.printd()
The output is as follows:
MyMeta called with
clsname: <class '__main__.Kls'>
args: ('arun',)
arun
Equipped with this information, if we go to the start of our discussion about the class creation process, it ended with a call to the metaclass object, which provided a class object. It was like this:
Kls = MetaClass(name, bases, attrs)
Hence this call should call the metaclass's type. The metaclass type is the metaclass's metaclass! We can check this as follows:
Python 3.x
class SuperMeta(type):
def __call__(metaname, clsname, baseclasses, attrs):
print('SuperMeta Called')
clsob = type.__new__(metaname, clsname, baseclasses, attrs)
type.__init__(clsob, clsname, baseclasses, attrs)
return clsob
class MyMeta(type, metaclass=SuperMeta):
def __call__(cls, *args, **kwargs):
print('MyMeta called', cls, args, kwargs)
ob = object.__new__(cls, *args)
ob.__init__(*args)
return ob
print('create class')
class Kls(metaclass=MyMeta):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
print('class created')
ik = Kls('arun')
ik.printd()
ik2 = Kls('avni')
ik2.printd()
Python 2.x
class SuperMeta(type):
def __call__(metaname, clsname, baseclasses, attrs):
print 'SuperMeta Called'
clsob = type.__new__(metaname, clsname, baseclasses, attrs)
type.__init__(clsob, clsname, baseclasses, attrs)
return clsob
class MyMeta(type):
__metaclass__ = SuperMeta
def __call__(cls, *args, **kwargs):
print 'MyMeta called', cls, args, kwargs
ob = object.__new__(cls, *args)
ob.__init__(*args)
return ob
print 'create class'
class Kls(object):
__metaclass__ = MyMeta
def __init__(self, data):
self.data = data
def printd(self):
print self.data
print 'class created'
ik = Kls('arun')
ik.printd()
ik2 = Kls('avni')
ik2.printd()
Gives us the following output:
create class
SuperMeta Called
class created
MyMeta called class '__main__.Kls' ('arun',) {}
arun
MyMeta called <class '__main__.Kls' ('avni',) {}
avni
For example:
Python 3.x
# Here __metaclass__ points to the metaclass object.
class ExampleClass(metaclass=type):
pass
Python 2.x
# Here __metaclass__ points to the metaclass object.
class ExampleClass(object):
__metaclass__ = type
pass
When a class is created, the interpreter:
Gets the name of the class.
Gets the base classes of the class.
Gets the metaclass of the class. If it is defined, it will use this first. Otherwise, it will check in the base classes for the metaclass. It it can't find a metaclass in the base class, the type object is used instead.
Gets the variables/attributes in the class and stores them as a dictionary.
Passes this information to metaclass as metaclass(name_of_class, base_classes, attributes_dictionary) and it returns a class object.
For example:
# type(name, base, attrs)
# name is the name of the class
# base is a tuple of base classes (all methods/attributes are inherited
# from these) attrs is a dictionary filled with the class attributes
classObject = type('ExampleClass', (object,) ,{})
When type is called, its __call__ method is called. This method in turn calls the __new__ and __init__ methods. The __new__ method creates a new object, whereas the __init__ method initializes it. We can easily play with methods. This is a working example:
Python 3.x
class a:
def __init__(self, data):
self.data = data
def getd3(self):
return self.data * 3
class MyMeta(type):
def __new__(metaname, classname, baseclasses, attrs):
print('New called with')
print('metaname', metaname)
print('classname', classname)
print('baseclasses', baseclasses)
print('attrs', attrs)
attrs['getdata'] = a.__dict__['getd3']
# attrs['getdata'] = a.getd3
return type.__new__(metaname, classname, baseclasses, attrs)
def __init__(classobject, classname, baseclasses, attrs):
print('init called with')
print('classobject', classobject)
print('classname', classname)
print('baseclasses', baseclasses)
print('attrs', attrs)
class Kls(metaclass=MyMeta):
def __init__(self,data):
self.data = data
def printd(self):
print(self.data)
ik = Kls('arun')
ik.printd()
print(ik.getdata())
When running the code, we get:
New called with
metaname <class '__main__.MyMeta'>
classname Kls
baseclasses ()
attrs {'__module__': '__main__', 'printd': <function printd at 0x7f3ebca86958>, '__init__': <function __init__ at 0x7f3ebca868d0>}
init called with
classobject <class '__main__.Kls'>
classname Kls
baseclasses ()
attrs {'__module__': '__main__', 'getdata': <function getd3 at 0x7f3ebca86408>, 'printd': <function printd at 0x7f3ebca86958>, '__init__': <function __init__ at 0x7f3ebca868d0>}
arun
arunarunarun
Python 2.x
class a(object):
def __init__(self, data):
self.data = data
def getd3(self):
return self.data * 3
class MyMeta(type):
def __new__(metaname, classname, baseclasses, attrs):
print 'New called with'
print 'metaname', metaname
print 'classname', classname
print 'baseclasses', baseclasses
print 'attrs', attrs
attrs['getdata'] = a.__dict__['getd3']
# attrs['getdata'] = a.getd3
return type.__new__(metaname, classname, baseclasses, attrs)
def __init__(classobject, classname, baseclasses, attrs):
print 'init called with'
print 'classobject', classobject
print 'classname', classname
print 'baseclasses', baseclasses
print 'attrs', attrs
class Kls(object):
__metaclass__ = MyMeta
def __init__(self, data):
self.data = data
def printd(self):
print self.data
ik = Kls('arun')
ik.printd()
print ik.getdata()
When running the code, we get:
New called with
metaname <class '__main__.MyMeta'>
classname Kls
baseclasses (<type 'object'>,)
attrs {'__module__': '__main__', '__metaclass__': <class '__main__.MyMeta'>, 'printd': <function printd at 0x7fbdab0176e0>, '__init__': <function __init__ at 0x7fbdab017668>}
init called with
classobject <class '__main__.Kls'>
classname Kls
baseclasses (<type 'object'>,)
attrs {'__module__': '__main__', 'getdata': <function getd3 at 0x7fbdab017500>, '__metaclass__': <class '__main__.MyMeta'>, 'printd': <function printd at 0x7fbdab0176e0>, '__init__': <function __init__ at 0x7fbdab017668>}
arun
arunarunarun
Normally we need to override only one method __new__ or __init__. We can also use function instead of a class. Here is an example:
Python 3.x
def meta_func(name, bases, attrs):
print('meta function called with', name, bases, attrs)
nattrs = {'mod' + key:attrs[key] for key in attrs}
return type(name, bases, nattrs)
MyMeta = meta_func
class Kls(metaclass=MyMeta):
def setd(self, data):
self.data = data
def getd(self):
return self.data
k = Kls()
k.modsetd('arun')
print(k.modgetd())
Gives us the following output:
meta function called with Kls () {'setd': <function setd at 0x7f3bafe7cd10>, '__module__': '__main__', 'getd': <function getd at 0x7f3bafe7cd98>}
arun
Python 2.x
def meta_func(name, bases, attrs):
print 'meta function called with', name, bases, attrs
nattrs = {'mod' + key:attrs[key] for key in attrs}
return type(name, bases, nattrs)
MyMeta = meta_func
class Kls(object):
__metaclass__ = MyMeta
def setd(self, data):
self.data = data
def getd(self):
return self.data
k = Kls()
k.modsetd('arun')
print k.modgetd()
Gives us the following output:
meta function called with Kls (<type 'object'>,) {'setd': <function setd at 0x88b21ec>, 'getd': <function getd at 0x88b22cc>, '__module__': '__main__', '__metaclass__': <function meta_func at 0xb72341b4>}
arun
Other then modifying base classes and methods of classes to be created, metaclasses can also modify instance creation process. This is because when we create an instance (ik = Kls()), this is like calling the class Kls. One point to note is that whenever we call an object its type's __call__ method is called. So in this case the class type is metaclass hence its __call__ method will be called. We can check like this:
Python 3.x
class MyMeta(type):
def __call__(clsname, *args):
print('MyMeta called with')
print('clsname:', clsname)
print('args:', args)
instance = object.__new__(clsname)
instance.__init__(*args)
return instance
class Kls(metaclass=MyMeta):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
ik = Kls('arun')
ik.printd()
Python 2.x
class MyMeta(type):
def __call__(clsname, *args):
print 'MyMeta called with'
print 'clsname:', clsname
print 'args:' ,args
instance = object.__new__(clsname)
instance.__init__(*args)
return instance
class Kls(object):
__metaclass__ = MyMeta
def __init__(self,data):
self.data = data
def printd(self):
print self.data
ik = Kls('arun')
ik.printd()
The output is as follows:
MyMeta called with
clsname: <class '__main__.Kls'>
args: ('arun',)
arun
Equipped with this information, if we go to the start of our discussion about the class creation process, it ended with a call to the metaclass object, which provided a class object. It was like this:
Kls = MetaClass(name, bases, attrs)
Hence this call should call the metaclass's type. The metaclass type is the metaclass's metaclass! We can check this as follows:
Python 3.x
class SuperMeta(type):
def __call__(metaname, clsname, baseclasses, attrs):
print('SuperMeta Called')
clsob = type.__new__(metaname, clsname, baseclasses, attrs)
type.__init__(clsob, clsname, baseclasses, attrs)
return clsob
class MyMeta(type, metaclass=SuperMeta):
def __call__(cls, *args, **kwargs):
print('MyMeta called', cls, args, kwargs)
ob = object.__new__(cls, *args)
ob.__init__(*args)
return ob
print('create class')
class Kls(metaclass=MyMeta):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
print('class created')
ik = Kls('arun')
ik.printd()
ik2 = Kls('avni')
ik2.printd()
Python 2.x
class SuperMeta(type):
def __call__(metaname, clsname, baseclasses, attrs):
print 'SuperMeta Called'
clsob = type.__new__(metaname, clsname, baseclasses, attrs)
type.__init__(clsob, clsname, baseclasses, attrs)
return clsob
class MyMeta(type):
__metaclass__ = SuperMeta
def __call__(cls, *args, **kwargs):
print 'MyMeta called', cls, args, kwargs
ob = object.__new__(cls, *args)
ob.__init__(*args)
return ob
print 'create class'
class Kls(object):
__metaclass__ = MyMeta
def __init__(self, data):
self.data = data
def printd(self):
print self.data
print 'class created'
ik = Kls('arun')
ik.printd()
ik2 = Kls('avni')
ik2.printd()
Gives us the following output:
create class
SuperMeta Called
class created
MyMeta called class '__main__.Kls' ('arun',) {}
arun
MyMeta called <class '__main__.Kls' ('avni',) {}
avni
Pythonのメタプログラミング (メタクラス)
メタクラスを簡単に説明すると,「本来コードを書かなければ実現できないような処理を黒魔術的な処理でなんとかしちゃう」ためのテクニックです。コード量を(時には劇的に)減らすことができたり,すっきりした見通しの良いクラス設計を実現できます。
JavaScriptのPrototypeのような継承が可能なPythonのクラスを作ることにしましょう。Pythonのクラス設計とJavaScriptのそれの間には異なる部分があるので,魔法を使ってこの差を埋める必要があります。
まずはコードを見てみましょう。これがPythonでJSのPrototypeを実現するメタクラスです。コードをproto.pyというファイル名で保存しておきましょう。
#!/usr/bin/env python
## -*- coding: utf-8 -*-
class PrototypeStore(dict):
""" x.prototype.XXXの値を保存するためのクラス """
def __setattr__(self, name, value):
self[name] = value
def __getattr__(self, name):
return self[name]
class PrototypeMeta(type):
""" Prototypeメタクラス(クラス生成時に呼ばれる) """
def __new__(metacls, cls_name, bases, attrs):
cls = type.__new__(metacls, cls_name, bases, attrs)
cls.prototype = PrototypeStore()
return cls
class Prototype(object):
__metaclass__ = PrototypeMeta
def __getattr__(self, name):
if name == 'prototype':
getattr(self.__class__, name)
else:
try:
getattr(object, name)
except AttributeError:
return self.__class__.prototype[name]
class TestClass(Prototype):
def __init__(self):
pass
ProtoMetaの__new__()メソッドとPrototypeの__metaclass__アトリビュートがキモ。
objectを継承した新スタイルクラスに__metaclass__というアトリビュートが設定されていると,クラスは特別な動きをします。クラス生成時に,__metaclass__のアトリビュートに設定されたクラスを起動し,__new__()メソッドを呼び出すのです。
__new__()メソッド内部を見ると,type.__new__()メソッドを呼び出してクラスを生成したあと,クラスのプロパティにprotopypeというアトリビュートを代入していることが分かります。代入されているのはProtoStoreクラスのインスタンス。ProtoStoreクラスは辞書型を継承したクラス。__setattr__()と__getattr__()を継承していて,アトリビュートの読み書きを辞書のキー操作に置き換え,任意の名前を持つアトリビュートを定義,値を保存して読み出せるオブジェクトが作れるようになっています。
type.__new__()で作ってクラスアトリビュートを割り当てられたクラスは,Prototypeクラス,およびそのサブクラスの実体として機能します。
インタラクティブシェルで「from proto import *」して,次のコードを実行してみましょう。JSのPrototypeの挙動をエミュレートした,期待通りの動きになっていることを確認します。
first = TestClass() # オブジェクトを作る
first.prototype.x = 7 # 'x'をprototypeに割り当てる
second = TestClass() # firstと同じTextClassからインスタンスを作る
print second.x # first.xと同じオブジェクトを指しているので7になる
first.x = 9 # first(インスタンス)の'x'アトリビュートに代入
print first.x # これは7でなく9を返す
del first.x # インスタンスのアトリビュートを消去
print first.x # prototype.xの返す7になるはず
禅問答
Q:Protytyoeクラスの__init__()で「self.prototype=PrototypeStore()」ってやればいいんじゃないの?
A:インスタンスごとにprototypeが定義されてしまって期待通りの動きにならない。
Q:クラスアトリビュートとして「prototype=PrototypeStore()」を定義すれば?
A:Prototypeクラス,および全てのPrototype由来のクラスで同じprototypeを共有することになり,同じく期待通りに動かない。すべてのサブクラスで「prototype=PrototypeStore()」ってやらないとならない。
Q:じゃあ__init__()で「self.__class__.prototype=PrototypeStore()」では?
A:それでもできるけど,Pythonではクラスを継承したときに__init__()が上書きされてしまうので,__init__()を定義したすべてのサブクラスで「super(XXX, self).__init__(...)」ってやらないといけない。面倒だしはまる原因になる。
JavaScriptのPrototypeのような継承が可能なPythonのクラスを作ることにしましょう。Pythonのクラス設計とJavaScriptのそれの間には異なる部分があるので,魔法を使ってこの差を埋める必要があります。
まずはコードを見てみましょう。これがPythonでJSのPrototypeを実現するメタクラスです。コードをproto.pyというファイル名で保存しておきましょう。
#!/usr/bin/env python
## -*- coding: utf-8 -*-
class PrototypeStore(dict):
""" x.prototype.XXXの値を保存するためのクラス """
def __setattr__(self, name, value):
self[name] = value
def __getattr__(self, name):
return self[name]
class PrototypeMeta(type):
""" Prototypeメタクラス(クラス生成時に呼ばれる) """
def __new__(metacls, cls_name, bases, attrs):
cls = type.__new__(metacls, cls_name, bases, attrs)
cls.prototype = PrototypeStore()
return cls
class Prototype(object):
__metaclass__ = PrototypeMeta
def __getattr__(self, name):
if name == 'prototype':
getattr(self.__class__, name)
else:
try:
getattr(object, name)
except AttributeError:
return self.__class__.prototype[name]
class TestClass(Prototype):
def __init__(self):
pass
ProtoMetaの__new__()メソッドとPrototypeの__metaclass__アトリビュートがキモ。
objectを継承した新スタイルクラスに__metaclass__というアトリビュートが設定されていると,クラスは特別な動きをします。クラス生成時に,__metaclass__のアトリビュートに設定されたクラスを起動し,__new__()メソッドを呼び出すのです。
__new__()メソッド内部を見ると,type.__new__()メソッドを呼び出してクラスを生成したあと,クラスのプロパティにprotopypeというアトリビュートを代入していることが分かります。代入されているのはProtoStoreクラスのインスタンス。ProtoStoreクラスは辞書型を継承したクラス。__setattr__()と__getattr__()を継承していて,アトリビュートの読み書きを辞書のキー操作に置き換え,任意の名前を持つアトリビュートを定義,値を保存して読み出せるオブジェクトが作れるようになっています。
type.__new__()で作ってクラスアトリビュートを割り当てられたクラスは,Prototypeクラス,およびそのサブクラスの実体として機能します。
インタラクティブシェルで「from proto import *」して,次のコードを実行してみましょう。JSのPrototypeの挙動をエミュレートした,期待通りの動きになっていることを確認します。
first = TestClass() # オブジェクトを作る
first.prototype.x = 7 # 'x'をprototypeに割り当てる
second = TestClass() # firstと同じTextClassからインスタンスを作る
print second.x # first.xと同じオブジェクトを指しているので7になる
first.x = 9 # first(インスタンス)の'x'アトリビュートに代入
print first.x # これは7でなく9を返す
del first.x # インスタンスのアトリビュートを消去
print first.x # prototype.xの返す7になるはず
禅問答
Q:Protytyoeクラスの__init__()で「self.prototype=PrototypeStore()」ってやればいいんじゃないの?
A:インスタンスごとにprototypeが定義されてしまって期待通りの動きにならない。
Q:クラスアトリビュートとして「prototype=PrototypeStore()」を定義すれば?
A:Prototypeクラス,および全てのPrototype由来のクラスで同じprototypeを共有することになり,同じく期待通りに動かない。すべてのサブクラスで「prototype=PrototypeStore()」ってやらないとならない。
Q:じゃあ__init__()で「self.__class__.prototype=PrototypeStore()」では?
A:それでもできるけど,Pythonではクラスを継承したときに__init__()が上書きされてしまうので,__init__()を定義したすべてのサブクラスで「super(XXX, self).__init__(...)」ってやらないといけない。面倒だしはまる原因になる。
2014年12月10日水曜日
仕事で使えるオープンソース・プロダクト10選
かつて有償パッケージが主流だったジャンルのソフトウェアでもオープンソースのプロダクトが増えてきています。最近では業務向けのもので、動きが顕著です。オープンソースだからといって、必ずしも機能的に劣るということはなく、むしろソースコードが未公開のパッケージ製品と比べて公開されていることから、機能追加やエラーの原因を追いやすいというメリットもあります。プロダクトによってはサポートだけ有償で提供するというライセンスモデルもあり、導入時はオープンソースライセンスを選択し、本格的に使う場合に商用ライセンスに切り替えるといった使い方ができるプロダクトもあります。ソースコードが公開されていることから、柔軟なカスタマイズが可能な上、エンジニアとして開発プロセスに貢献することができれば、スキル向上や実績にもなるという側面もあり、今やエンジニアにとってオープンソースのプロダクトとの付き合いは欠かせないものといっていいでしょう。
今回は、そんなオープンソースのプロダクトで、他のアプリケーションとの組み合わせも考慮して、比較的導入しやすい定番のものをカテゴリーごとに紹介します。
・CMS
WordPress
世界トップ1000万Webサイトの内、20%以上で採用され、全てのCMS中で60%を超えるシェアを有します。開発者が多いので進化、つまりバージョンアップされていくスピードが速く、欲しい機能がどんどん増えていきます。また、プラグインも豊富なので、自分で開発しながら新しい機能を取り込むことも容易と言えそう。そのためか、日本でも多くの企業が導入しています。
シェアが高いことにも関係しますが、デザインテンプレートが多数提供されており、開発者のイメージ通りにデザインできることも強みのひとつ。なお、テンプレートはPHPで記述されているので、カスタマイズにより機能追加も可能です。
■活用シーン……WordPressと言えば、"ブログ作成"のイメージが強いですが、本格的なECサイトとして活用することももちろん可能です。よく利用される買い物カゴ、予約管理、会員管理、カスタマイズ可能なフォーム機能などもプラグインで実現できるのはエンジニアにとって大変有益なことと言えるのではないでしょうか。
・販売管理
SalesCube
基本機能が充実しており、かつソース提供型なので、自在にカスタマイズできる販売管理システムとして、評価の高いオープンソースです。しかも、販売管理に関するアプリケーションの数は比較的少ないため、ある種、貴重とも言えます。
販売管理に必要とされる機能は、在庫管理・入出金・仕入れの管理など、ほぼ網羅されているのではないでしょうか。さらに発注面では海外仕入先も想定し、外貨にも対応。そうした機能面での充実が、今回のセレクトの理由になりました。
■活用シーン……エンジニアが悩むポイントですが、クライアントの業態や業務は企業により変わったり、同じ社内でも媒体や扱う商品によって違うこともあります。そのため、市販の販売管理パッケージとの業務マッチングが難しいケースも多く、一般的には「パッケージに業務を合わせる」ことになってしまいます。その点、「SalesCube」ならオープンソースなので、実務に合わせてカスタマイズしたシステムを構築することができます。
・CRM/顧客管理
SugarCRM
顧客の状態管理をするとき(データべースマーケティング:見込み客から始まって得意客に成長するまでのプロセス)にその真価を発揮するオープンソース。オープンソース版と有償版があり、有償版は確かに優秀ですが、少々高額です。オープンソース(Sugar Community Edition)版でも、取引先/取引先担当者管理・商談管理・メールマーケティング・会議管理・プロジェクト管理・従業員管理などの機能を持つので、スキルさえあるのであれば、わざわざ有償版を選ぶ必要はなさそう。
ほかにもいくつか顧客管理をするオープンソースは存在しますが、メルマガ配信サービスに機能を補足した程度のものが多く、日本では一部でしか活用例を見ない貴重なオープンソースでしょう。
■活用シーン……潜在顧客との関係性を深めていくために必要な情報を収集する機能があり(Web to Lead機能など)、それを活用することでメールサーバと連携し、メールマーケティングを実現することも可能。また、会議システムとの連携や販売代理店管理機能もあり、高度な営業支援を実現できます。
・プロジェクト管理
Redmine
中小企業がプロジェクト管理をする際に、もっとも適しているアプリケーションのひとつがこれ。複数のプロジェクト、あるいは多人数がかかわっているプロジェクトにおいて、細部まで管理できるようにしたい、といった要望には見事にマッチします。
中でも、ワークフローを見るだけで業務の進捗がわかる点は、管理者には大変好評な機能のひとつ。これに似たものの有償版も存在しますが、大企業向けに開発されているため、中小企業には使いづらい面も。中小企業には不要な機能と思われるものは排除されているため、エンジニアとしても使い勝手が非常にいいと言えます。
■活用シーン……社内の制作プロジェクトはもちろんのこと、業務をアウトソースした場合でも、作業の進捗や情報共有が容易。「プロジェクト管理ツールは使いたいが、機能が多すぎて煩雑」という事業者にRedmineを導入するケースも。
・グループウェア
Aipo
社内の情報共有管理に適したカスタマイズ可能なオープンソースグループウェア。製品版として、有償なものも数多くあるのですが、無償版のオープンソースのものでも手頃な機能が網羅されているためオススメです。TODO・掲示板・スケジュール・ニュース・ブログ・Webメール・ファイル共有機能など、グループウェアとしての十分な機能があり、それらをタイムライン形式で表示することもできます。
特徴的なのは、Aipoの機能を拡張できるソーシャルアプリが、専用ストアで公開されていること。数は少ないものの、外部デベロッパーが独自に開発したソーシャルアプリを組み込むことで、機能を追加することが可能です。
■活用シーン……既に公開されているソーシャルアプリには、女性の画像と時計を組み合わせた「美人時計」や、"飲み"へのお誘い機能「飲みイコ」なども。
ソーシャルアプリの開発手順も公開されているので、独自視点でのグループウェアの提案にも活用できます。
・Eコマース
EC-CUBE
EC構築オープンソースとして国内No.1(2010年調べ)の、ECサイト構築パッケージ。推定10,000 店舗以上で利用されている。Wordpress同様、シェアが高く、開発者が多いので進化、バージョンアップされていくスピードが速いです。つまり、欲しい機能がどんどん増えていくと言えます。また、プラグインも豊富なので、自分で開発しながら新しい機能を取り込むことも容易と言えそう。社内システムとの連携もしやすく、取り扱いやすいとも言えるでしょう。機能は、ECサイトの基本機能に加え、マイページ機能・決済機能・モバイル対応・商品管理・受注管理・顧客管理・メルマガの配信などの機能を網羅。
Eコマースは規模が拡大すると、ECサイト単体だけではなく、社内外のさまざまなサービスとの連携が必要になるため、高い拡張性が求められます。EC-CUBEは、連携に必要なプラグインを多数用意することにより、それを実現しています。
■活用シーン……ショッピングモールや、ASP型サービスから移行する際に、コストや機能面から候補として検討する事業者が多いようです。
・SNS
OpenPNE
Webコミュニティをオープンソースで立ち上げることができます。数多くあるCMSに比べてSNSは割と数が少ないので貴重なオープンソースとも言えます。
PC・スマートフォン・フィーチャーフォンのマルチデバイス対応した、オープン・クローズドで利用できるSNS。現在30,000以上のコミュニティに活用されています。コミュニティの新規作成・日記・メッセージ・あしあと・フレンドリンクなどの機能があります。
■活用シーン……Facebookなどのマス型SNSに対し、OpenPNEは地域・教育機関・企業・趣味のファンクラブなど、さまざまな組織に合ったSNSを始めることができます。
・Web会議システム
BigBlueButton
遠隔教育、講義を前提としたオープンソースのWeb会議システム。機能は、講義の配信・リアルタイムのデスクトップの共有・プレゼンテーション・チャット機能など。他のe-ラーニングシステムと組み合わせると有用性は高まります。
一般のWeb会議システムとは異なり、1対多の講義形式に適しており、他のオープンソース会議システムのベース機能としても採用されています。
■活用シーン……少人数であればSkypeやGoogle+ハングアウトも使えますが、参加者がIDやアカウントを持っていなければなりません。BigBlueButtonは接続先アドレスがわかればブラウザで会議が可能なので、使い勝手が良いでしょう。
・ファイル共有
ownCloud
簡単に言えば、Dropboxのようなツール。フォルダイメージでファイルをドラッグ&ドロップすることで、複数PC間でのファイルの移動、同期ができます。
自分のローカルPC内のフォルダをownCloud用フォルダに指定し、そのフォルダ内のファイルを更新すれば、ownCloudサーバ内のファイルが自動更新されます。また、Dropbox同様、違うPCにあるownCloud用フォルダも自動で同期可能。さらに複数ユーザ用の共有フォルダも作成できます。
■活用シーン……オンラインストレージツールは、容量やファイルサイズ制限、保持期間など、制約があることが多いですが、ownCloudを自前のサーバにインストールすれ無く活用することができます。
・動画配信プラットフォーム
Kaltura
マルチデバイスに対応した、動画配信専用のプラットフォーム。既に多数のメディア・広告・教育・エンタメ分野の150,000を超える企業サイトで、Kalturaの動画ソリューションが活用されています。
動画のアップロード・マルチプラットフォーム用の動画変換機能・暗号化・独自プレーヤーの作成・動画編集まで、動画配信に特化した一連の機能と、カスタマイズ用のAPIが用意されているため、柔軟な展開が可能。
■活用シーン……動画配信のプラットフォームとして、多くの場合「YouTube」が利用されていますが、CMなど、不必要な動画が入る場合があります。Kalturaを活用すれば、そういった制約なしに、課金型の動画配信や、会員制の教育などの、動画ビジネスを展開することができでしょう。
コストメリットや拡張性など、さまざまなメリットのあるオープンソース。初期導入は簡単でもカスタマイズに手間がかかるケースもああります。事業者の業態に向いているアプリケーションを選択することが必要です。オープンソースを使用した比較的安価なインテグレーションを提供している企業もあるので、それらを利用するのも手段のひとつかもしれませんね。
今回は、そんなオープンソースのプロダクトで、他のアプリケーションとの組み合わせも考慮して、比較的導入しやすい定番のものをカテゴリーごとに紹介します。
・CMS
WordPress
世界トップ1000万Webサイトの内、20%以上で採用され、全てのCMS中で60%を超えるシェアを有します。開発者が多いので進化、つまりバージョンアップされていくスピードが速く、欲しい機能がどんどん増えていきます。また、プラグインも豊富なので、自分で開発しながら新しい機能を取り込むことも容易と言えそう。そのためか、日本でも多くの企業が導入しています。
シェアが高いことにも関係しますが、デザインテンプレートが多数提供されており、開発者のイメージ通りにデザインできることも強みのひとつ。なお、テンプレートはPHPで記述されているので、カスタマイズにより機能追加も可能です。
■活用シーン……WordPressと言えば、"ブログ作成"のイメージが強いですが、本格的なECサイトとして活用することももちろん可能です。よく利用される買い物カゴ、予約管理、会員管理、カスタマイズ可能なフォーム機能などもプラグインで実現できるのはエンジニアにとって大変有益なことと言えるのではないでしょうか。
・販売管理
SalesCube
基本機能が充実しており、かつソース提供型なので、自在にカスタマイズできる販売管理システムとして、評価の高いオープンソースです。しかも、販売管理に関するアプリケーションの数は比較的少ないため、ある種、貴重とも言えます。
販売管理に必要とされる機能は、在庫管理・入出金・仕入れの管理など、ほぼ網羅されているのではないでしょうか。さらに発注面では海外仕入先も想定し、外貨にも対応。そうした機能面での充実が、今回のセレクトの理由になりました。
■活用シーン……エンジニアが悩むポイントですが、クライアントの業態や業務は企業により変わったり、同じ社内でも媒体や扱う商品によって違うこともあります。そのため、市販の販売管理パッケージとの業務マッチングが難しいケースも多く、一般的には「パッケージに業務を合わせる」ことになってしまいます。その点、「SalesCube」ならオープンソースなので、実務に合わせてカスタマイズしたシステムを構築することができます。
・CRM/顧客管理
SugarCRM
顧客の状態管理をするとき(データべースマーケティング:見込み客から始まって得意客に成長するまでのプロセス)にその真価を発揮するオープンソース。オープンソース版と有償版があり、有償版は確かに優秀ですが、少々高額です。オープンソース(Sugar Community Edition)版でも、取引先/取引先担当者管理・商談管理・メールマーケティング・会議管理・プロジェクト管理・従業員管理などの機能を持つので、スキルさえあるのであれば、わざわざ有償版を選ぶ必要はなさそう。
ほかにもいくつか顧客管理をするオープンソースは存在しますが、メルマガ配信サービスに機能を補足した程度のものが多く、日本では一部でしか活用例を見ない貴重なオープンソースでしょう。
■活用シーン……潜在顧客との関係性を深めていくために必要な情報を収集する機能があり(Web to Lead機能など)、それを活用することでメールサーバと連携し、メールマーケティングを実現することも可能。また、会議システムとの連携や販売代理店管理機能もあり、高度な営業支援を実現できます。
・プロジェクト管理
Redmine
中小企業がプロジェクト管理をする際に、もっとも適しているアプリケーションのひとつがこれ。複数のプロジェクト、あるいは多人数がかかわっているプロジェクトにおいて、細部まで管理できるようにしたい、といった要望には見事にマッチします。
中でも、ワークフローを見るだけで業務の進捗がわかる点は、管理者には大変好評な機能のひとつ。これに似たものの有償版も存在しますが、大企業向けに開発されているため、中小企業には使いづらい面も。中小企業には不要な機能と思われるものは排除されているため、エンジニアとしても使い勝手が非常にいいと言えます。
■活用シーン……社内の制作プロジェクトはもちろんのこと、業務をアウトソースした場合でも、作業の進捗や情報共有が容易。「プロジェクト管理ツールは使いたいが、機能が多すぎて煩雑」という事業者にRedmineを導入するケースも。
・グループウェア
Aipo
社内の情報共有管理に適したカスタマイズ可能なオープンソースグループウェア。製品版として、有償なものも数多くあるのですが、無償版のオープンソースのものでも手頃な機能が網羅されているためオススメです。TODO・掲示板・スケジュール・ニュース・ブログ・Webメール・ファイル共有機能など、グループウェアとしての十分な機能があり、それらをタイムライン形式で表示することもできます。
特徴的なのは、Aipoの機能を拡張できるソーシャルアプリが、専用ストアで公開されていること。数は少ないものの、外部デベロッパーが独自に開発したソーシャルアプリを組み込むことで、機能を追加することが可能です。
■活用シーン……既に公開されているソーシャルアプリには、女性の画像と時計を組み合わせた「美人時計」や、"飲み"へのお誘い機能「飲みイコ」なども。
ソーシャルアプリの開発手順も公開されているので、独自視点でのグループウェアの提案にも活用できます。
・Eコマース
EC-CUBE
EC構築オープンソースとして国内No.1(2010年調べ)の、ECサイト構築パッケージ。推定10,000 店舗以上で利用されている。Wordpress同様、シェアが高く、開発者が多いので進化、バージョンアップされていくスピードが速いです。つまり、欲しい機能がどんどん増えていくと言えます。また、プラグインも豊富なので、自分で開発しながら新しい機能を取り込むことも容易と言えそう。社内システムとの連携もしやすく、取り扱いやすいとも言えるでしょう。機能は、ECサイトの基本機能に加え、マイページ機能・決済機能・モバイル対応・商品管理・受注管理・顧客管理・メルマガの配信などの機能を網羅。
Eコマースは規模が拡大すると、ECサイト単体だけではなく、社内外のさまざまなサービスとの連携が必要になるため、高い拡張性が求められます。EC-CUBEは、連携に必要なプラグインを多数用意することにより、それを実現しています。
■活用シーン……ショッピングモールや、ASP型サービスから移行する際に、コストや機能面から候補として検討する事業者が多いようです。
・SNS
OpenPNE
Webコミュニティをオープンソースで立ち上げることができます。数多くあるCMSに比べてSNSは割と数が少ないので貴重なオープンソースとも言えます。
PC・スマートフォン・フィーチャーフォンのマルチデバイス対応した、オープン・クローズドで利用できるSNS。現在30,000以上のコミュニティに活用されています。コミュニティの新規作成・日記・メッセージ・あしあと・フレンドリンクなどの機能があります。
■活用シーン……Facebookなどのマス型SNSに対し、OpenPNEは地域・教育機関・企業・趣味のファンクラブなど、さまざまな組織に合ったSNSを始めることができます。
・Web会議システム
BigBlueButton
遠隔教育、講義を前提としたオープンソースのWeb会議システム。機能は、講義の配信・リアルタイムのデスクトップの共有・プレゼンテーション・チャット機能など。他のe-ラーニングシステムと組み合わせると有用性は高まります。
一般のWeb会議システムとは異なり、1対多の講義形式に適しており、他のオープンソース会議システムのベース機能としても採用されています。
■活用シーン……少人数であればSkypeやGoogle+ハングアウトも使えますが、参加者がIDやアカウントを持っていなければなりません。BigBlueButtonは接続先アドレスがわかればブラウザで会議が可能なので、使い勝手が良いでしょう。
・ファイル共有
ownCloud
簡単に言えば、Dropboxのようなツール。フォルダイメージでファイルをドラッグ&ドロップすることで、複数PC間でのファイルの移動、同期ができます。
自分のローカルPC内のフォルダをownCloud用フォルダに指定し、そのフォルダ内のファイルを更新すれば、ownCloudサーバ内のファイルが自動更新されます。また、Dropbox同様、違うPCにあるownCloud用フォルダも自動で同期可能。さらに複数ユーザ用の共有フォルダも作成できます。
■活用シーン……オンラインストレージツールは、容量やファイルサイズ制限、保持期間など、制約があることが多いですが、ownCloudを自前のサーバにインストールすれ無く活用することができます。
・動画配信プラットフォーム
Kaltura
マルチデバイスに対応した、動画配信専用のプラットフォーム。既に多数のメディア・広告・教育・エンタメ分野の150,000を超える企業サイトで、Kalturaの動画ソリューションが活用されています。
動画のアップロード・マルチプラットフォーム用の動画変換機能・暗号化・独自プレーヤーの作成・動画編集まで、動画配信に特化した一連の機能と、カスタマイズ用のAPIが用意されているため、柔軟な展開が可能。
■活用シーン……動画配信のプラットフォームとして、多くの場合「YouTube」が利用されていますが、CMなど、不必要な動画が入る場合があります。Kalturaを活用すれば、そういった制約なしに、課金型の動画配信や、会員制の教育などの、動画ビジネスを展開することができでしょう。
コストメリットや拡張性など、さまざまなメリットのあるオープンソース。初期導入は簡単でもカスタマイズに手間がかかるケースもああります。事業者の業態に向いているアプリケーションを選択することが必要です。オープンソースを使用した比較的安価なインテグレーションを提供している企業もあるので、それらを利用するのも手段のひとつかもしれませんね。
登録:
投稿 (Atom)