ホーム > タグ > プログラミング言語

プログラミング言語

より良いPHPerになるための20Tips

Write clearly php code

去年の話ですが、海外でこんな記事が上がっていました。

記事の内容は、かなりレベルが低いです。
しかし、初心者のうちに知っておけば、より早く成長出来るでしょう

初心者PHPerのために、この記事の翻訳を載せます。

2011年03月21日 追記

この記事の補足が、他の方によって書かれています。
この記事に対する自分の意見を、先に載せておくべきだったかも。
実は色々と痛い目を見ると、この下の記事の悪いところと、上記記事の良いところがわかります
だけど、初めはわからないんですよね…。

20 Tips you need to learn to become a better PHP Programmer

PHPは、同じオブジェクトの扱い方でも複数の書き方を持っている、とても気まぐれなプログラミング言語だ。
詳しくは、私の書いた”The Art of Programming“を読むと良い。
これから書くTipsは、過去のプロジェクトから私が学んだコードの可読性、メンテナンス性を上げ、あなたを素晴らしい、より進んだPHPプログラマーにするものだ。

それじゃ、始めよう。

1. <?phpと?>を使え

スクリプトを書くにあたり、<?と?>を使うのを忘れること。
これらを使ったスクリプトがあなたのサーバで動いたとしても、他のサーバで動かないかもしれない。

同様に、変数をechoするときもショートタグを使うのを止めるんだ。
慣れた人がこれを使うのを止めるのは、正直、難しい。
けど、止めることで最終的にポータブルなコードが書けるんだ。

<? ... ?> // Incorrect
<?php ... ?> // Correct
<?=$Var?> // Incorrect
<?php echo $Var ?> // Correct

2. 設定ファイルを分離せよ

あなたのスクリプトファイルに設定値が追加すべきであるということは、言うまでもないよね。
あなたはいつでも、設定ファイルを分離して、スクリプトの頭でインクルードすべきだ。
こうしておけば、設定を書き換える必要が出てきても、設定ファイルの一部を書き換えるだけで良い。
ファイルのインクルードはとても簡単だ。

<?php
include("config.php");

// code goes here ...

3. コメントは君の友達

そう、あなたはこんな状況に遭遇したことがあるんじゃ?
私たちが少し前に書いたコードを理解出来なくなるのは、本当に驚くべきことだ。
コメントは、そのときに考えていたことを思い出させてくれる。
シンタックスはこう。

<?php
// Line One Comment
// Line Two Comment

/** Paragraph Comment
Paragraph Comment
Paragraph Comment **/

簡単でしょ?

4. インデントとスペースを使え

まったく正しくインデントされていない、誰が書いたかわからないコードを変更することほど、最低なことはないね。
正しくインデントされたコードは、あなたがプログラマーだってことを示している。
理想的なコードは、ループがそこで終わりだか、終わりでないんだか、が一目で分かるんだ。
これは、不適切にインデントされたコードだ。

<?php
function  dothisformula($a,$b) { $c = $b+$a;
     $e=3;
while ($c < 20) {
$e = $e - 1; $c = $c + 1; }
     return $e; }

そして、こっちが正しいコード。

<?php
function dothisformula($a, $b) {
     $c = $b + $a;
     $e = 3;
     while ($c < 20) {
          $e = $e - 1;
          $c = $c + 1;
     }
     return $e;
}

スペースの重要性が分かった?

5. 変数名に意味を持たせよ

変数に意味を持たせることは、いつもあなたのためになる。
データの型まで分かると、更に良い。
例えば、integer型の変数には、変数名のプレフィックスとしてiをつける。
変数に型宣言しないPHPにおいて、これは特に重要だ。

変数名の頭文字を大文字にするかどうかは、あなた次第だ。
しかし、読み易さから言っても、単語の先頭は大文字にすることをお勧めする。

こんな感じだ。

<?php
$iNumber = 10; // For Integers

$sName = "Marc"; // For Strings

$fPi = 3.14159265; // For Floats

$aNames = array(); // For Arrays

$oUser = new User(); // For Objects

$bIsMember = false; // For Booleans

6. 変数を初期化せよ

PHPでは、変数に値を代入するたびに、自動で変数を定義してくれる。
しかし、変数を使う前に初期化するのは、良い癖だ。
これをすることで、コードが明確になるし、変数の内容があなたの思い通りの値になる。

<?php
$aArray = array();
$iInteger = 0;
$bBoolean = false;
Boolean is False, unless True

7. 返り値は常にFalseに、Trueじゃない限りは

もし、あなたが特定の値であるか、どうかを判定するコードを書いたとする。
そのコード判定は望む値になった場合を除き、常にfalseを返すべきだ。
例えば、以下のようなコードは書かない方が良い。

<?php
function getStatus() {
    $bReturn = true;
    if ($i != 2) $bReturn = false;
    return $bReturn;
}

この代わりに、あなたはこう書くべきだ。

<?php
function getStatus() {
    $bReturn = false;
    if ($i == 2) $bReturn = true;
    return $bReturn;
}

二番目の例は、値をチェックする場合の理想的な方法だ。
なぜかって?あなたがデータベースから値を取り出すときを、想像してみて欲しい。
もし、何かしらの理由で、あなたの書いたif文が間違っていたら?
この書き方をしていれば、間違った値に対して、常にfalseが返る。
私たちが、PHPでsensitiveなデータを取り扱うなら、正しいデータが入力されるまでは、動かないコードを書くべきだ。
これは私の経験上、特にね。

最終的に、バリデーションとは、あなたのデータがあなたの思い描く通りであるか、それともそうでないかを判断するべきものだ。

8. 配列のキーにアクセスする場合はクオートで囲う

配列にアクセスする場合、以下のどちらのコードでもPHPでは動く。

<?php
$sName = $aNames['marc'];
$sName = $aNames[marc];

二つ目のコードは、PHPはまず始めに、marcと名付けられた定数を探しに行き、もし存在すればその値に置き換える。
そう、大抵の場合、これでも動く。
しかし、もし、同じ名前の定数が定義されていたら?
その場合、あなたのスクリプトは動作しなくなるんだ。

9. echoするときにはコンマを使え

もし、文字列を変数の値と一緒に出力するとき、PHPではドットの代わりにコンマを使うことが使える。
なぜ?ドットを使うよりも僅かに速いからね(以下のコードでテストした場合は)。

<?php
echo "Hello, my name is ", $sName;

以下の代わりに上記のコードを使う。

<?php
echo "Hello, my name is " . $sName;

10. 三項演算子を使え

もし、シンプルなif文を書きたいなら、三項演算子を使って、ワンラインで通常のif文を書くのと同じことが書ける。

<?php
if ($a == 1) $b = 2;
else $b = 3;

上記のコードは、以下の三項演算子を使ったのと同じことだ。

<?php
$b = ($a == 1) ? 2 : 3;

簡単でしょ?三項演算子は、以下のようによく使われるね。

<?php
$variable = (CONDITION) ? IFTRUE : IFFALSE;
Use === for Boolean Checks

11. 真偽値のチェックには===を使え

もし、あなたが変数がtrueかfalseか、チェックしなければ行けない場合、==よりも===を使おう。
この三つ連なるイコールは、PHPに値のチェックと同時に、タイプのチェックまでさせる。

<?php
if ($bIsMember == true) { ... } // Incorrect
if ($bIsMember === true) { ... } // Correct
Use ++ and — Operators

12. ++と–の演算子を使え

整数を減少あるいは増加させる場合、インクリメントあるいはデクリメントの演算子が使える。
もし、あなたがこんなコードを書いているなら、

<?php
$iNumber = $iNumber  + 1;
$iNumber2 = $iNumber2 - 1;

こう変換すべきだ。

<?php
$iNumber++;
$iNumber2--;

この演算子の優れているところは、他演算の実行中にも使えることだ(例えば、ifとかwhileのステートメントだ)。
++とか–の演算子は、変数の前に置くか、後に置くかで、動作が異なる。
前に置けば、その動作が完了する前に、後に置けば、その動作が完了した後にインクリメント、あるいはデクリメントが実行される。
以下の例は、あなたの、この演算子の理解を助けてくれるだろう。

<?php
$iNumber = 10;
while ($iNumber++ == 10) { ... }
// インクリメント演算子が、比較後に実行される。
//  つまり、このwhileの中は1度だけ実行される。

$iNumber = 10;
if (--$iNumber == 10) { ... }
// デクリメント演算子が、比較前に実行される。
// つまり、このwhileの中は1度も実行されない。 

$iNumber = 10;
$iTotal = $iNumber++;
// $iTotalは10だ。

$iNumber = 10;
$iTotal = --$iNumber;
// $iTotalは9だ。

13. 代入演算子を使え

もし、あなたが2以上の数値をインクリメントあるいは、デクリメントしたいとする。
その場合、代入演算子が便利だ。
もし、こんなコードがあったとしたら、

<?php
$a = $a + $b;
$a = $a * 5;
$a = $a - $d;
$a = $a / 3;

代入演算子を使って、次のように書き直せる。

<?php
$a += $b;
$a *= 5;
$a -= $d;
$a /= 3;

これは、もちろん文字列にも使える。次の二行のコードは同じ意味だ。

<?php
$sString = $sString . "hello";
$sString .= "hello";

14. 変数のdump関数を作れ

私たちは、テストをする上で変数の値を確認するためによく、print_rにはお世話になる。
これをさらに簡単にするために、次のような関数を作ろう。

<?php
function p($var) {
    echo "<pre>";
    print_r($var);
    echo "</pre>";
}

これはあなたの変数dumpを常に、読みやすいようにpreタグで括る物だ。
ついでに、関数名を一文字にすることで、使いやすくもなる。

15. 定数を使え

もし、変更されない変数を使ってるんだとしたら、それは書き直せる必要はないよね。
よくアクセスする、例えばディレクトリパスやエラーメッセージなどは、定数化しよう。
定数名には、全て大文字を使うことをお勧めする。
こうすることで、コード中でそれが定数であることが、わかりやすくなる。

<?php
define ("DIRECTORY","/path/to/site/");

echo DIRECTORY;

16. $_GETと$_POSTを使え

$_REQUEST変数のことは忘れよう。
URLからGETパラメータが欲しいときは$_GETを、フォームからPOSTパラメータが欲しいときは、$_POSTを使おう。

<?php
$sAction = $_GET['actions'];

$sName = $_POST['name'];

こうすることで外部のユーザは、URLを操作することによって、フォームの値を変更出来なくなる。

17. 関数の代わりにオブジェクトを使え

もし、たくさんの引数と共に関数を使っていたのなら、それはオブジェクトに移行するときが来たのだ。
私は、メンテナンスのしにくい、とても複雑な関数が定義されているプロジェクトで働いていたこともある。
そう、引数が20個もある関数がいくつか定義されているのだ。
こんなとき、あなたは変数の呼び出し方法を変更する必要があるだろう、それも全ての関数において。
この関数では、

<?php
function getProducts($iParameter1, $iParameter2,
$iParameter3, $iParameter4, $iParameter5,
$iParameter6, $iParameter7, $iParameter8,
 $iParameter9) { ... }

こう変更することが出来る。

<?php
$oProducts->setParameter1(...);
$oProducts->setParameter3(...);
$oProducts->setParameter5(...);
$oProducts->setParameter6(...);
$oProducts->getProducts();

18. メソッドチェインを使え

もし、あなたが複数回オブジェクトのメソッドを呼び出し、変数にセットするなら、メソッドチェインを使うことで、コードをシンプルに出来る。
メソッドチェインの方法は簡単で、各メソッドに返り値に$thisをセットするだけだ。
次のコードは、

<?php
class User {

    function setThis($iVar) {
        ....
        return $this;
    }

    function setThis2($iVar2) {
        ....
        return $this;
    }

}

次のようにメソッドチェインに書き換えることが出来る。

<?php
$oUser = new User();
$oUser->setThis(...)
      ->setThis2();

これであなたのコードは、より短く、より素晴らしくなるよ。

19. コードの繰り返しを止めよ

どんなコードも繰り返すな。もし、少しでも同じコードを書いていたなら、それは関数に置き換えてしまえ。
それか、オブジェクトに変えてしまえ。この作業は面倒かもしれない。
しかし、アプリケーションが大きくなればなるほど、その対価を支払う価値がある。
簡単な例は以下だ。

<?php
$a = 1;
while ($a < 10) {
    $b = $a * 10;
    $c = $b * 2;
    $d = $c * $b;
    echo $d;
    $a++;
}

これは、次のように書き換えれる。

<?php
function multiply($iVar, $iVar2) {
     return ($iVar*$iVar2);
}

$a = 1;
while ($a < 10) {
    $b = multiply($a, 10);
    $c = multiply($b, 2);
    $d = multiply($c, $b);
    echo $d;
    $a++;
}

もちろん、これはとても簡単な例だ。
この方法は、コードの繰り返し箇所が多くなればなるほど、より便利になる。

20. 結合度を減らし、独立性を保て

結合度は一つのコンポーネントを変えたときに、どれだけのコンポーネントに影響を与えるか、ってことだ。
言い方を変えると、もしあなたがある関数を変えたとして、他の関数を変える必要があるかどうか、ということ。
結合度を下げること、それはつまり、他に影響を与えないようにコンポーネントを変更することだ。
一方で、独立性はそれぞれを意味のあるユニットに分けることだ。
あなたのメイン関数は、全てのことを担ってる?
それとも、たくさんの特定の仕事をする関数から出来てる?
もし、そうなら、強い独立性を持っていることになる。強い独立性を持つと、その関数の責任が明確になり、その関数が自分に関係ない処理を行う場合に、他の関数を呼び出すようになる。

PHPプログラマの諸君は、コンポーネントを定義する場合、アプリケーションのメンテナンスを楽に、そして拡張性を高めるために、結合度を弱くし、独立性を強くするように気をつけるべきだ。
例え、関数を一つ作るだけであっても、このことは心に留めておくべきだ。
独立性の高いコードを常に正しく追加しよう。
そうすれば、あなたがシステムの一部を変更する場合に、他の部分を変更しなくても良くなるんだ。

こんなコードがあったとしよう(もちろん、これはシンプルな例だが)

<?php
// We want to add two numbers
// only if the first number is
// lower than 5

function add($iVar, $iVar2) {
    if ($iVar < 5) return false;
    else $iResult = $iVar+$iVar2;
    echo "The Result is ", $iResult;
}

$iVar = 3;
$iVar2 = 2;
add($iVar, $iVar2);

この例は、バリデーションを関数内に含んでいることで、独立性が弱く、結合度が高くなってしまっている。
結果の出力を関数内に置くことは、それ自体大きな問題だ。
もし、この関数を複数箇所で使っていたとして、テキストを変更したい場合に、全ての箇所の変更を考慮しなければいけないのだから。

もっと良いのは次のコードだ。

<?php
// We want to add two numbers
// only if the first number is
// lower than 5

function addd($iVar, $iVar2) {
    return $iVar + $iVar2;
}

function result($sMessage) {
    return "The Result is " . $sMessage;
}

$iVar = 3;
$iVar2 = 2;

if ($iVar < 5) {
    echo result(add($iVar, $iVar2));
}

こうすることで、addとresultの関数をコードの至る所で使うことが出来る。
そして、他のコードを気にすることなく、各関数を変更することが出来るんだ。

最後に

このTipsは分かりやすく、短く、そしてよりまとまったコードを書くのを助けてくれる。
これらの例はとてもシンプルだが、それぞれのコンセプトを理解するのに役立つものだ。
もし、あなたがこれらの一つにでも同意出来ないなら、ブログにコメントを。
私たちはそこからさらに、学べる。

おまけ

もし、あなたがPHPプログラマなら、公式のPHPドキュメントはあなたのバイブルだ。
私は、それぞれのセクションを眺めて、各関数でどんなことが出来るのか確認することをお勧めする。
あなたは、PHPで用意された既製関数で多くのことが実現できることに、驚くはずだ。

この記事があなたの役に立つことを。
どんなコメントでも待ってます。
ありがとう!

個人的な感想

この記事に書かれている内容は、レベルがかなり低いです。
例えば、”4. インデントとスペースを使え”。
これはプログラマとしては、当たり前のことです。

しかし、ここに書かれている大半のことは、多くの初心者PHPerが迷うことでもあります。
記事の途中でもありますが、PHPは”多くの書き方が出来る気まぐれな言語“です。
だからこそ、これらのことを知らずに、何となくプログラムが書けるようになったとき、そこで満足してしまい、良いコードが書けなくなるのでしょう。

私自身、PHPを始めたときに、この記事を知っていればもっと早く良いコードが書けるようになったのでは、と思います。

初心者PHPerの皆さんは、この記事を足がかりに、コードを洗練させていってください
(個人的なおまけ: より良いコードを書くには、より良い人のコードを読むことが大事ですよ!)

“初めてのPython”を、1週間で攻略する6つのポイント

calender_python.jpg

以前に”Pythonの勉強をまったく始められないあなたと私に送る8つのタスク“という記事を書きました。

この記事を覚えていますか?
皆さん、この通りにタスクを消化出来ているでしょうか

自分で目標を立てておいて申し訳ないのですが、自分はステップ1で早速遅れが生じました
初めてのPython“はなかなか手強く、このタスクを消化するのに2週間を使ってしまいました。

そもそも、この”初めてのPython“に挫折した人も多いはず。
前回の記事についたはてブのコメントを見てそれを感じました。
総ページ数が768、付録を抜いても700ページはあります。

これを2週間で読了するには”作戦”が必要です。

私自身、”初めてのPython“には一度挫折しています。
あの記事を書いたのが2回目の挑戦であり、3度目の正直、ではなく2度目の正直でした。

その経験と、個人的に知っている読書スキルを踏まえて、”1週間で初めてのPythonを攻略する6つのポイント“をまとめてみます。
皆さんは1週間で”初めてのPython“を読めるように。

1. 計画を立てる

まず、計画を立てましょう。
計画とは期限と、その期限を守るためにタスクを分割すること。

実は”初めてのPython“は1週間で読むのに、ちょうど良く構成されています

  1. Pythonの基礎知識
  2. ビルドインオブジェクト
  3. ステートメント
  4. 関数
  5. モジュール
  6. クラスとオブジェクト指向プログラミング
  7. 例外

7部構成になっているんです。
つまり、単純に1日1部読めば良いんです

それぞれボリュームがあります
しかし、それは残り4つのポイントを踏まえれば読める量だと思います。

2. 読まない

速く読む方法、それは”読まない“ことです。
読まなければ、”読む時間“は掛かりませんからね。

とは言え、読まなければ知識は得られません。
そこで、以下の二つを念頭に置きながら読んでいきます

  1. 2回読んで理解出来ない部分は読み飛ばす
  2. コードを中心に理解する

これを実践するだけで読むのは格段に速くなるはず。

2回読んで理解出来ない部分は読み飛ばす

理解出来ない点を読み飛ばすのは不安ですが、2回読んで理解出来ないところは”自分の実力が足りない“か、”理解するのに情報が足りないか“のいずれか。

自分の実力が足りないのは、もうどうしようもありません。
諦めましょう(笑)
そのうち理解出来るようになります。

理解するのに情報が足りないのは、その先を読めば理解出来ます。
本において情報はいくつかの文や段落で成り立ちます。
作者はいくつかの文や段落を通して、1つのことを伝えようとしています。
つまり、理解出来ない部分で悩むのは無駄
どんどん先に進みましょう。
そのうち、理解出来ますよ。きっと。

コードを中心に理解する

Pythonはある意味、”WYSIWYG“な言語です。
つまり、長々と説明されるよりも、コードを見た方が早いことが多いです。
ざっと説明を読み、腹落ちさせるのはコード。
初めてのPython“には分かりやすいコードがたくさん載っています。
 
私自身、こういった読み方で”初めてのPython“を攻略しました。

3. メモをとる

これだけの分量の本です。
ものすごく記憶力の良い方であれば良いのですが、私を含めた凡人には読みながら記憶することは出来ないでしょう
だからこそ、メモを取ります
ポイントを書き出すのではなく、各部毎にまとめたメモを作ります。

私はマインドマップで1部ずつまとめていきました。
雑ですが、これで十分かと。

learning_python_mindmap.png

とにかく時間との勝負なので、ざっと必要なところをまとめます。
あとで見直すので、ページ数もメモすると良いと思います。
私はページ数のメモを忘れて、対象のページを探すのに時間が掛かりました…。
付箋を使うのもありですね!

4. Pythonの中心を把握する

学生時代、教官になんて言われたか覚えていますか?
特に中学かな。

必ず、授業の予習/復習してこいよ。

大人になると、これを忘れがちです。
“Pythonの中心を把握する”というのは、”Pythonを予習する“ってことです。

Pythonの中心、それは

クラスはもちろん、関数やモジュールが全てオブジェクトである。

ということです。
初めてのPython“ではこの話が中心となり、Pythonの説明が書かれています。
これを念頭に置くだけで理解が早まるはずです。

あら、もう予習出来てしまいましたね!

5. 手早く予習する

各部を読んでいくのも、必ず予習します
全体像をつかんでから、読み進めます。
こうすると、自分が必要としているところだけを読むことが出来ます。

予習に使うのは目次1-byte.jpです。
(ブログの宣伝ではないですよ:D)

まず、各部を読む前に”目次“に目を通し、どんなことが書かれているか把握します。
ほう、なるほど。こんなことが書かれているのか。“と。

それが終わったら、1-byte.jpで各部をまとめた記事があるので、それに目を通します。

これだけで十分な気がしてくる?
これは個人的な勉強メモに過ぎません。
それぞれ必要とする情報は違うはず。
あくまで”どんなことが書かれているか”の把握に使ってください。

そして、本当に本当に、本当にあなたが必要な情報を”初めてのPython“から抜き取ってください。

6. 実践する

時間があれば、理解を深めるためにコードを書いてください

部の最後に”まとめの問題集“があるのですが、これは読み飛ばしてOKです。
それよりも、自分でまとめた内容を自分で実践してみてください。
そうすると、理解が間違っていた点が浮き彫りになります。

学習は”トライ & エラー“だと思います。

“実践する”ということはまさにそれで、理解を深めます。
私はブログにまとめる“という方法で、これを実践しました。
ブログにまとめるために、かなり間違ったコードを書きました。

ただ、ここまでやると時間が足りなさそうな、そんな気がします。
ここは、別ステップに分けても良いかもしれませんね

どうですか?
1週間で”初めてのPython“が読める気がしてきましたか?

あれだけ厚い本です。
頭から読もうとしないでください
自分が必要なところだけ読んでしまえば良いんです。
頭から読もうとすると、読む前に心が折れてしまいます

Pythonの勉強をまったく始められないあなたと私に送る8つのタスク“の記事はたくさんの方に読んでもらい、とても嬉しかったです。
あれだけのはてブがついたのも初めてでした。
(実はあの記事のせいで、ブログの更新がちょっと止まってしまったのですが…それは別の話)

タスクとその期限を決めておいて、放置するのも無責任だと思ったので、”初めてのPython“の総括がてら、こんな記事を書いてみました。

Pythonはすごく良い言語だと思います。
一人でも勉強する人が増えれば個人的には嬉しいです。
一緒に勉強出来ますしね。

引き続き、Pythonista目指して頑張りましょう!

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

初めてのPython(7) 例外に関する簡単なまとめ

先週はPHP Matsuriの準備と後片付けでPythonを勉強する時間が取れませんでした…。
かなりの時間を使ったと思うのですが、その分楽しめたと思います。
どんなイベント?“と少しでも興味があるかたはこちらを。

PHP Matsuriのまとめも書いていきたいのですが、その前に勉強したPythonの例外をまとめておきます。
忘れないうちにやっておかないと、綺麗さっぱり頭の中から消え去ってしまうので…。

ちょっと期間が空いてしまいましたが、Pythonの例外についてまとめます。

初めてのPython VII部

初めてのPythonのVII部には”例外“がまとめられています。
構文が中心に、少しだけその設計に関することも書かれています。

例外処理というのは奥が深いものです。
そもそも、簡単なWebアプリケーションを作っているだけでは、例外に触れる機会がありません
PHPもPythonも、簡単なアプリケーションでは設計者が気にしなくても、”良きに計らって“くれますからね。

それだけに、”エラーが起こりえる“プログラムを書くときにどう書けば良いかわからなくなってしまうんです。
簡単なWebアプリケーションから、より深い部分に触れるプログラムを書き始めたときにエラー処理さえ書かないこともしばしば(それは自分のことです :D)。

そういった”エラーが起こりえる状況への対処“を認識する上で、このVII部は重要だと思います。
どんなときに例外を使うのか、どんなときにtry,else,finalyの構文を使うのか。
初めてのPython“のVII部を読めば、このイメージをつかめます。

プログラマーとしてのレベルを上げるためにも読んでおきたいところです。

ここでは簡単な構文と、その動作についてまとめます。
例外の設計を語るほど、プログラマーとしてのレベルは高くないので…。

例外の種類

Pythonには2種類の例外があります。

  • 文字列例外
  • クラス例外

これらには、読んで字の通り、例外の内容が”文字列“か、”クラス“かの違いがあります。
コード数は”文字列例外“のほうが少なくなります。
しかし、色々と使い勝手が良いのは”クラス例外“です。

# 文字列例外
raise "This is Exception string."

# クラス例外
class EggException(BaseException): pass
raise EggException()

クラス例外は”クラス“を別に定義する必要がある分、コードが長くなります
文字列例外は”文字列“を例外として渡すだけなので、コードが短くなります

しかし、例外を捕まえ、事後処理をする場合の話は別です。
この場合、この二つの例外でコードの長さはほとんど変わりません
結局、同じロジックを書くことになるためです。
問題はどこにそのロジックを書くか。

# 文字列例外
stringException = "This is Exception"
try:
	raise stringException
except e:
	print "Got Exception."

# クラス例外
class ClassException(BaseException):
	def printException(self):
		print "Got Exception."

try:
	raise ClassException()
except ClassException, E:
	E.printException()

文字列例外では例外を捕まえる度にロジックを書きます
クラス例外ではクラスの1メソッドとして、ロジックを書いておき、そのメソッドを呼び出します
演算子のオーバーロードをうまく使えば、メソッドを呼び出す必要もありません。

ここで違いが出るのは、コードの見やすさですね。
クラスに例外処理を全てまとめることができ、見やすいコードが出来上がります。

その他には”関連する(継承した)クラスを捕まえることが出来る”こともクラス例外の特徴として上げられます。

# 親クラスの定義
class ParentClassException(): pass
# サブクラスの定義
class SubClassException(ParentClassException): pass

# 親クラスを指定して、サブクラスの例外を捕まえることが出来る。
try:
	raise SubClassException()
except ParentClassException:
	print "Got Exception."

そして、ここまで説明しておいて申し訳ないのですが、文字列例外は2.6以降のバージョンでは廃止されています
今まで見てきた通り、クラス例外のほうが使いやすいためです。
文字列例外は”簡単に書ける“こと以外にメリットがありませんから。
Pythonでは構文を統一させるために、こういった仕様変更がよく起こるようですね。

クラス例外では、これらの特性を利用して、色々な例外処理を設計出来そうです。
例外の設計を別に勉強したいですね。
アーキテクチャ系の本を読めば良いのかな?

例外を捕まえる

先ほどから簡単な例外を捕まえる例を書いています。
しかし、Pythonには他にも例外を取り扱う構文があります。

  • raise
    • 例外を発生させる。
  • assert
    • 条件が合致した場合にだけ、例外を発生させる。
  • try/except
    • tryの中で例外があった場合に、exceptのロジックを実行する。
  • try/finally
    • tryの中での例外の有無に関わらず、finalyのロジックを実行する。
  • with/as
    • コンテキストマネージャと呼ばれる高度な例外処理を実行する。

ここで重要な構文はraisetry/except、それにtry/finallyでしょう。

class EggException(BaseException):
  what = 'This is EggException'
class SpamException(BaseException):
  what = 'This is SpamException'

try:
	# この中で起こった例外が補足される。

	### 以下のいずれかのraiseのコメントを外して実行する。
	# EggExceptionのインスタンスを例外として投げる。
	#raise EggException() #これを実行すると、exceptの中が実行される。
	# SpamExceptionのインスタンスを例外として投げる。
	#raise SpamException() #これを実行すると、elseの中が実行される。
	# EggExceptionクラスのオブジェクトを例外として投げる。
	#raise EggException #これを実行すると、exceptの中が実行される。

	# 例外が発生した場合、ここは実行されない
	print 'Not execute'

# EggExceptionを補足する。他の例外は無視。補足した例外を変数eに入れる。
except EggException, e:
	print e.what

# BaseExceptionを継承した例外を補足する。補足した例外は変数eに入れる。
else BaseException, e:
	print e.what

# 例外の有無に関わらず、実行する。
finally:
	print 'every time'

これが基本形ですね。
例外として投げることが出来るのは、”オブジェクト“です。
従って、クラスのインスタンスやクラスそのものを投げることが出来ます。
先ほどの例では、”raise EggException”がこれにあたります。

そのため、先ほど”文字列例外は廃止された”と書きましたが、文字列のオブジェクトを例外として投げることは出来ます。

try:
	raise 'This is test.'
except:
	print 'Got Exception.'

その他に数字もOK。

try:
	raise 1000
except:
	print 'Got Exception.'

さらに、tryがない場合はどうなるのか?

“例外が発生したオブジェクトを呼び出しているオブジェクト”に例外が渡されます。

一番簡単な例はこれです。

def egg():
	raise BaseException

try:
	egg()
except:
	print 'Got Exception'

この例ではegg関数の中にtry/exceptはないのですが、それを呼び出しているメインモジュールにはtry/exceptがあります。
そのため、このメインモジュールで例外が補足されています。
これはどれだけネストが深くなっても同じです。
もちろん、クラスでも、モジュールでも。

python_exception.png

例外に関してはこんなところでしょうか。
もっと色々と説明したいのですが、長くなってしまいます。
詳しく知りたい方は是非、初めてのPythonを買ってください。

これで、Pythonの基礎は一通り終わりです。
次は指にPythonを慣れさせる段階ですね!

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

初めてのPython(6) Pythonでオブジェクト指向プログラミングを

初めてのPython“も残り1部です。
ここまで長かった…ですが、とても勉強になりました。
Pythonを学び、”PHPには何が足りないのか“を自分の中で消化出来たような気がします。
それではラストスパートに入って行きましょう。

初めてのPython VI部

初めてのPython“のVI部には”Pythonにおけるオブジェクト指向プログラミング“がまとめられています。
クラスメソッドの構文はもちろんのこと(これがないとクラスを書けませんしね…)、オブジェクト指向の考え方まで。

has-a関係やデリゲーション、ファクトリといった”オブジェクト指向プログラミングの基本的な設計“までもまとめてあります。
このあたりの話はPythonに限ったことではないので、”オブジェクト指向プログラミング“の経験がある方は読み飛ばせると思います。
ただ、単純な構文だけでなく、このような根本の考え方を含めて学べるのは”初めてのPython“の良いところかな、と。

これまでの内容を理解しているのであれば、VI部の内容を理解するのは容易いでしょう。
構文だけを学び、ソースコードを眺めるだけでも良さそうです。

ここでは”オブジェクト指向プログラミング“の経験があることを前提に、Pythonでのオブジェクト指向プログラミングをまとめていきます。

クラスとインスタンス

Pythonではクラスも”オブジェクト“です。
そしてインスタンスも”オブジェクト“です。

全てオブジェクトで扱う。それがPythonです。

そして、クラス宣言も”オブジェクト“を生成し、それを”クラス名の変数“に入れる操作にしか過ぎません。

class Spam:
	def printMe(self):
		print self

SpamCopy = Spam
spamIns = SpamCopy()
spamIns.printMe()
# spamInsがSpamのインスタンスであることが表示される。
# <__main__.Spam instance at 0x7f779b318518>

このように書くことで、クラスを別の変数に入れることも出来ます。

また、インスタンスの生成も変わっていますよね。
関数の呼び出しと同じ宣言の仕方でインスタンスが出来てしまいます。

メソッドも関数と同じ”def“を使います。
ただし、第一引数に”self“を使う点が異なります。
先ほどの例で分かったと思いますが、この”self“には呼び出した自分自身(インスタンス)が入ります。

PHPやJavaで言うところの”this“ですね。
Pythonではこれを明示的にメソッドに示します。
これが結構分かりやすい。

class Spam:
	num = 0
	def add(self):
		self.num += 1
	def getNum(self):
		return self.num

spamIns = Spam()
spamIns.add()
print spamIns.getNum()
# 1が表示される
spamIns.add()
print spamIns.getNum()
# 2が表示される

self“が何者かだけ分かっていれば、扱いやすいと思います。
クラスオブジェクト自身が持つメソッドを使うことだって出来ますよ。

class Spam:
	num = 0
	def add(self):
		self.num += 1
	def getNum(self):
		return self.num

spamIns = Spam()
Spam.add(spamIns)
print Spam.getNum(spamIns)
# 1が表示される
Spam.add(spamIns)
print spamIns.getNum(spamIns)
# 2が表示される

つまり、インスタンスのメソッドを呼び出すときは、Pythonが自動でクラスオブジェクトのメソッドの第一引数を埋めてくれているんです
内部的に何か訳の分からないことをやられるよりは、こっちのほうがずっと分かりやすいです。
クラスとインスタンスの関係を知っていれば良いんですから。

クラスって何?“と聞かれれば、”それは単なる名前空間にしか過ぎない。“と答えることが出来そうです。
class宣言の後には、”名前空間“が出来上がります。
その中に”変数( = 属性)“や”関数( = メソッド)“を宣言していると考えれば良いんです。
だからこそ、”def add(self):“や”num = 0“といった今までと同じ書き方が出来る。

話は戻りますが、クラス宣言も単なる”オブジェクトの生成“と”そのオブジェクトへのリファレンスを持った変数の生成“にしか過ぎません。
そのため、こんなことも出来ます。

class Spam:
	num = 0
	def add(self):
		self.num =+ 1

class Spam:
	num = 0
	def sub(self):
		self.num =- 1
	def getNum(self):
		return self.num

spamIns = Spam()

spamIns.sub()
print spamIns.getNum()
# -1が表示される

spamIns.add()
# エラーが発生する

PHPだと”クラスの二重宣言だ!“って怒られてしまいますよね。
この柔軟性がPythonの素敵なところです。

他にPythonのクラスの特徴として、属性が”ディクショナリ“で管理されていることが上げられます。

class Spam:
	def attributes(self):
		self.egg = 'egg'
		return self.__dict__

spam1 = Spam()
print spam1.attributes()
# {'egg': 'egg'}が表示される。

演算子のオーバーロード

Pythonのクラス宣言で嬉しいのが、この”演算子のオーバーロード“です。
これは何か?“というとインスタンスに対する演算子の処理を独自に定義出来ます
つまり、プラス(+)やマイナス(-)がインスタンスに対して実行出来るんです。

class Company:
	workers = 0
	def __add__(self, other):
		newCompany = Company()
		newCompany.workers = self.workers + other.workers
		return newCompany

	def __sub__(self, other):
		newCompany = Company()
		newCompany.workers = self.workers - other.workers
		return newCompany

company1 = Company()
company1.workers = 10
company2 = Company()
company2.workers = 20

company3 = company1 + company2
print company3.workers
# 30が表示される

company4 = compony2 - company1
print company4.workers
# 10が表示される

ただし、同じクラスのインスタンス同士の演算でない場合、対象のインスタンスが演算子の左右どちらかに書かれるかで動作が変わってきます。
自分自身、あまり理解していないのと、まずは基本形だけ覚えれば良いと思うので、ここではこれだけにしておきます。

Pythonでは”コンストラクタ“も演算子のオーバーロードの一つです。
インスタンスを生成するときに使用する”引数指定“をオーバーロードするイメージでしょうか。

class Company:
	def __init__(self, workers = 0):
		self.workers = workers

company1 = Company()
print company1.workers
# 0が表示される

company1 = Company(20)
print company1.workers
# 20が表示される

演算子のオーバーロードを使えば、クラスに”指定された属性“がない場合の処理も簡単に書けます。

class Company:
	def __getattr__(self, name):
		if name == 'name':
			return '1-byte.jp'
		else:
			# 属性がない場合の例外を発生させる
			raise AttributeError

company1 = Company()
print company1.name
# 1-byte.jpが表示される
print company1.type
# エラーが発生する

その他に、”リスト表記“にも対応することが出来ます。

class Spam:
	def __getitem__(self, num):
		return num * 2

spam1 = Spam()
print spam1[1]
# 2が表示される
print spam1[11]
# 22が表示される

しかし、便利ですね。
色々活用のアイディアが広がります。

継承と多重継承

Pythonではもちろん、”多重継承“も出来ます。
(PHPでは出来ないんですがね…)

class Person:
  name = None
  sex = None

  def __init__(self, name, sex):
    self.name = name
    self.sex = sex

  def getName(self):
    return self.name

  def getSex(self):
    return self.sex

class Printer:
  def __str__(self):
    return str(self.__dict__)

class Worker(Person, Printer):
  job = None

  def __init__(self, name, sex, job):
    Person.__init__(self, name, sex)
    self.job = job

worker1 = Worker('John', 'male', 'engineer')

print worker1
# {'job': 'engineer', 'name': 'John', 'sex': 'male'}が表示される
print worker1.getName()
# 'John'が表示される
print worker1.getSex()
# 'male'が表示される

しっかり継承されていることがわかります。
と、ここで気づいたのですが、(多重継承でない)継承の説明をしていませんでしたね。

class クラス名(継承するクラス名):

このステートメントを書くことで、クラスを継承出来ます。
先ほどのコードで分かったと思いますが、多重継承の場合は、

class クラス名(継承するクラス名1, 継承するクラス名2, 継承するクラス名3, …):

と書きます。
属性“や”メソッド“の検索順は書いた順番です。つまり、左側に書いたクラスから順に検索されます

class Spam1:
	name = 'Spam1'

class Spam2:
	name = 'Spam2'

class Spam3(Spam1, Spam2): pass

class Spam4(Spam2, Spam1): pass

spam = Spam3()
print spam.name
# 'Spam1'と表示される

spam = Spam4()
print spam.name
# 'Spam2'と表示される

これだけ理解していれば基本は大丈夫です。

ちょっと複雑な話をすると、継承する形によって検索順が問題になることがあります。
いわゆる”ダイアモンド継承“と呼ばれる形です。

多重継承したクラスを先に検索するのか?それとも、親クラスを先に検索するのか?

このあたりの話は面倒なので、ここには書きません。
知りたいという方は、SIBUKAWAさんの以下の記事が参考になります。

長くなったので、”Pythonのオブジェクト指向プログラミング”の話はここで終わりにしましょう。
本当は”どうやってスタティックメソッドを作るのか“、”情報を隠蔽するのか“など、細かい話は尽きません。

私自身、”初めてのPython“を読みましたが、全てを理解し、活用出来るようになった訳ではありません。
このあたりになってくると、テクニック的な話が多くなりますね。
その辺は自分でアプリケーションを作りながら、ソースコードを読みながら勉強しましょう。

次で”初めてのPython“シリーズは最後です。
ブログ書きながら読んだら2週間かかっちゃいましたね…。

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

初めてのPython(5) importとfromとreloadでモジュールを使いこなす

初めてのPython“も佳境ですね。
あと2部読み進めればおしまいです。
初めてのPython“を全て読むことが出来れば、Pythonistaとしての第一歩を踏み出せたことになります(自分の中で)。

初めてのPython V部

初めてのPython“のV部は、”モジュール“に関してまとられています。
Pythonにおけるモジュールのインポートの仕方や、再読み込みその扱いまで。

と、”その前にモジュールって何?“という方のためにWikipediaから引用しておきます。


プログラミングにおいて、一連の機能をひとまとまりになる複数の機能:モジュールに分割し、それぞれ別に開発する場合がある。こうすることで、全体として完成を早めることが出来る上、モジュール単位でテストしたりすることが可能になり、モジュールの入れ替えで機能を高めたり補修したりすることができるようになる。

モジュール – Wikipediaより

そして、モジュールとクラスの違いは、以下の通り。


ジュールとクラスの違いは以下の通りである。
クラスにはインスタンスとしてオブジェクトを生成する機能がある。
クラスは他のクラスの動作やデータを継承することができる。
ポリモーフィズムにより、クラスのインスタンス間の関係は実行時に変化するが、モジュール間の関係は静的である。
モジュールとクラスの類似点は以下の通りである。
どちらも実装の詳細を外部から隠蔽する。
どちらも階層(モジュール階層とクラス階層)を形成することができる。

モジュール – Wikipediaより

普段、PHPを使っているのでこの”モジュール“という概念が頭にありませんでした。
PHPではインポート(require)すると、C言語のインポート(include)と同じで、”ファイル自体がそこに読み込まれる“という動作をしますからね。
インポートだけでは、名前空間が別に分かれたりしないわけです。

こういう構造もあってか、PHPではモジュールをすっ飛ばしてクラスを使います。
そのため、私自身、”モジュール“は初体験でした。

このあたりの話になってくると、色々と絡み合ってくるので、読むのに苦労しました。
最後の応用の部分は理解出来たか、自身がありませんが、基本は押さえたので、これをまとめていきます。

モジュール

Pythonにおける”モジュール”とは、

ファイル

です。

これが一番分かりやすいでしょう。”モジュール” = “ファイル“なのです。

以前の記事を覚えているでしょうか?

この記事からスコープの画像を引用します。

このファイルにあたる部分が、Pythonでは”モジュール“と呼ばれます。

この図から分かる通り、Pythonではファイル間でスコープを共有しません
そのため、ファイルごとに機能を独立してコードを記述することが出来るのです。
機能を独立して記述できる…だから、Pythonではファイルが”モジュール“なのです。

Pythonではこの”モジュール”も”オブジェクト“として扱います。
モジュールを読み込むためにはimportステートメントを使います。

オブジェクトである証拠をソースコードで示しましょう。
ファイル構造は次の図の通りとします。

python_module_import.png

これらのファイルの中身は次のソースコードとします。

spammer.py

import spam

print spam.x

spam.py

x = 20

egg.py

import spam

spam.x = 10

import spamer

egg.pyを実行した結果として出力されるのは”20“ではなく、”10“です。
モジュールがオブジェクトとして扱われるために、このような動作となります。

今までの”可変性/不変性“や”リファレンス“の考え方を理解していれば、この動作はしっくり来ます。
importステートメントは“モジュールオブジェクト”へのリファレンスを作り出す操作なのです。

また、説明していませんが、モジュール内の変数へはドット(.)を使って自由にアクセス出来ます。
モジュール内にある変数を呼び出すときは、

[モジュール名].[変数名]

関数を呼び出すときは、

[モジュール名].[関数名](引数)

という形を取ります。
クラスと同じような使い方なので、オブジェクト指向プログラミングをした人にとっては理解しやすいかと。

モジュール = ファイル
分かりやすいし、書きやすいと思いませんか?

import

先ほど説明した通り、importステートメントは、”モジュールオブジェクトへのリファレンス“を作り出します。

1度目のimportステートメントは“モジュールオブジェクト”を生成し、そのリファレンスを設定します。
2度目以降のimportステートメントは生成済みの”モジュールオブジェクト”へのリファレンスを設定します。

spam.py

x = 30

egg.py

import spam

spam.x = 10

# spamモジュールをsecond_spamという名前でインポートする
import spam as second_spam

print second_spam.x

egg.pyを実行した結果は”10“です。
モジュール内の変数が上書きされてしまっていることが分かります。
importステートメントで設定した変数はあくまで、”モジュールオブジェクトへのリファレンス“にしか過ぎません。

python_multiple_import.png

importの基本はこれだけです(多分)。

from

fromはimportの拡張です。

spam.py

x = 10

egg.py

from spam import x
print x

これだけです。

え、わからない?

モジュールの中の”変数”や”関数”を指定して、読み込んでいるんです

importステートメントはモジュールをまるごと”オブジェクト”として読み込む方法でした。
fromステートメントは、そのオブジェクト内にあるオブジェクトへのリファレンスを、インポート元のスコープに設定します。

python_from_import.png

このため、先ほどのimportと同じようなコードを書いても、同じ結果にはなりません(変数が上書きされてしまうからね)。

spam.py

x = 30

egg.py

from spam import x

x = 10

# eggモジュールのxオブジェクトをyという名前でコピーする
from spam import x as y

print y
# 30が表示される

しかし、可変性のオブジェクトだと話は別です。
こんなことが出来ます。

spam.py

x = []

egg.py

from spam import x

x.append(1)

# eggモジュールのxオブジェクトをyという名前でコピーする
from spam import x as y

print y
# [1]が表示される

どうでしょう。
なぜこうなるか、わかりますか?
説明するのが難しいですね…これまた、”オブジェクト“と”リファレンス“の関係です。
理解出来ない“という方は前の記事を読んでみてください。

reload

個人的に面白い使い方が出来そうと思ったのが”reload“です。
名前の通り、モジュールを再読み込みします。

先ほど、importは”1度目の呼び出し時だけオブジェクトを生成する“と説明しました。
これは、”1度目の呼び出し時だけソースコードをコンパイルしてオブジェクト化する“ことを示します。
つまり、ソースコードはimportを使う限り、1度だけしか読み込まれないんです

これを2度、3度と読み込むのが”reload“です。

例えばこんなコードを書いてみます。

spam.py

print 'spam'

egg.py

import time
import spam

while 1:
  reload(spam)
  time.sleep(5)

egg.pyを実行すると、5秒おきにspam.pyを読み込みます。
放っておくと、永遠と”spam”と言い続けるでしょう。

これをターミナルで実行した上で(プログラムを強制終了させずに)、spam.pyを書き換えます

spam.py

print 'spam and egg'

あら不思議、”spam and egg”を連呼するようになりました(うるさいのは変わりないですけどね)。

この”reload“、使い道を間違えなければ強力な武器になりそうです。
プログラムを止めずに、モジュールを差し替えることが出来るんですから

モジュールについて簡単にまとめてみました。
実はまだたくさん書いていないことがあります。
例えば、モジュール内の変数の隠蔽モジュールの自己診断パッケージのインポートなどです。

初めてのPython“のV部は”簡単なのに、難しい“です。
このあたりは理解よりも、慣れが大きいんでしょうね。

あぁ、Pythonでプログラムが書きたくなってきた!

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

初めてのPython(4) 関数でさえオブジェクトであるPython

やっと、”初めてのPython“のIV部を読み終わりました。
初めてのPython“の読書はすごく順調に進んでいます。
そう、すごく順調に…。

そこには触れないようにして、今日のPythonのまとめに行きましょう。

初めてのPython IV部

初めてのPython“のIV部は、”関数“についてまとめてあります。

え、関数なんて余裕だよ。“という人も、読み飛ばさずに読んでください。
Pythonにおける関数も他の言語とちょっと変わっています

PHPの関数宣言functionにあたる宣言がPythonではdefです。
この宣言を使って、Pythonではこんなことが出来ちゃいます。

def create_memory(x, y):
	def memory():
		return x, y
	return memory

mem = create_memory(2, 3)
print mem()
# (2, 3)が表示される

関数をネストして、値をネストした関数内に保持させています。

これが出来るのも全て”関数がオブジェクト“だからです。

IV部ではこの”関数がオブジェクト“であることのメリットや、その使い方を説明しています。

関数オブジェクト

先ほども述べた通り、Pythonでは関数でさえオブジェクトとして扱います。
それはこのコードを見れば簡単に分かるでしょう。

def add(x, y):
	return x + y

print add(1, 2)
# 3が表示される

my_add = add
print my_add(1, 2)
# 3が表示される

print my_add
# <function add at 0x7f0be1e095f0>が表示される。0x7f0be1e095f0は実行時によって違う。

関数を作っておき、それ自体(関数)を変数に代入する“ということがPythonでは簡単に出来てしまいます。

Pythonは本当に何から何までオブジェクトです。

柔軟性の高い引数

Pythonで関数を指定する場合は、次のように引数を渡します。

  • 通常
    • 一般的な引数の順番で指定する方法。
  • キーワード
    • 引数の名前と共に値を指定する方法。順序関係なし。
  • デフォルト
    • 一般的な方法。デフォルト値を引数に設定出来る。ただし、Pythonならではの癖がある。
  • 可変
    • 可変引数も指定可能。指定された引数をタプルまたはディクショナリで受け取ることが出来る。

Pythonでは柔軟性が高く、かつコードが少なくなるように設計されています。
キーワード引数や可変引数は色々と活用出来そうです。

通常“はイメージにお任せします。
恐らく私とあなたが抱いているイメージは同じでしょう。

キーワード“はこのような指定が出来ます。

def spam(x = 1, y = 1, z = 1):
	return x, y, z

print spam(y = 2)
# (1, 2, 1)が表示される。
print spam(y = 2, x = 10)
# (10, 2, 1)が表示される。

デフォルト“は先ほどのキーワードの例でも使いましたが、引数に”デフォルト値“を設定する方法です。

def spam(x = 10):
	return x

print spam()
# 10が表示される。
print spam(20)
# 20が表示される。

何度もしつこいですが、Pythonでは全てがオブジェクトです。
それによって起きる癖のあるコードを紹介します。

def spam(y, x = []):
	x.append(y)
	return x

print spam(y = 1)
# [1]が表示される。
print spam(y = 2)
# [1, 2]が表示される。
print spam(y = 3)
# [1, 2, 3]が表示される。

Pythonではデフォルト値でさえ、オブジェクトとして扱ってしまうのです。
“x”に指定しているデフォルト値は”空のリスト“です。
リストは可変性のオブジェクト
可変性のオブジェクトは、変更を加えてしまうと、それを参照している変数全てに影響があります。

Pythonは関数オブジェクト作成時にデフォルト値のオブジェクトも作成します
このデフォルト値にオブジェクトを持つ関数オブジェクトを何度も呼び出すことで、例のように内容がどんどん追加されることになります。

可変“は次のように可変長の引数を渡すことが出来ます。

def spam(*x):
	return x

print spam(1)
# (1, )が表示される
print spam(1, 2)
# (1, 2)が表示される
print spam(1, 2, 3)
# (1, 2, 3)が表示される

可変で渡ってきた引数は、タプルとして引数に代入されます。

キーワード引数を”可変“にすることも出来ます。

def spam(**x):
	return x

print spam(z = 1)
# {'z':1}が表示される
print spam(z = 1, y = 2)
# {'z':1, 'y':2}が表示される
print spam(z = 1, y = 2, x = 3)
# {'y':2, 'x':3, 'z':1}が表示される

これらの引数指定は便利だと思いませんか?
なんだか、色々なことが出来そう…と想像してしまいます。

スコープを表すLEGBルール

関数を使う上で”スコープ“を理解することは重要です。
スコープって何?“と言う方はいないと思いますが、Wikipediaから引用しておきます。


プログラミングでのスコープとは、ある変数や関数が特定の名前で参照される範囲のこと。ある範囲の外に置いた変数等は、通常、その名前だけでは参照できない。このときこれらの変数はスコープ外である、「見えない」といわれる。

スコープ – Wikipediaより

簡単に言ってしまうと、”名前の影響範囲“ですね。

PythonではLEGBルールと名付け、その範囲が次のように決まっています。

  • L: Local scope
    • その関数内のみで有効なスコープ。
  • E: Enclosing function’s scope
    • その関数の外側内側の関数でのみ有効なスコープ。
  • G: Global scope
    • ファイル全体で有効なスコープ。
  • B: Built-in scope
    • プログラム全てで有効なスコープ。

図で示すと、このような形です。

python_scope.png

[2010/09/30 追記] 上記の図は間違っています。正しくはこちら。

python_scope.png

Local“は簡単に分かると思うので説明しません。
Pythonが他と少し違うのは”Enclosing function’s scope“と”Global scope“です。

Enclosing function’s scope“は一番始めに示したコードです。

def create_memory(x, y):
	def memory():
		return x, y
	return memory

mem = create_memory(2, 3)
print mem()
# (2, 3)が表示される

これはcreate_memory関数にネストされたmemory関数が、create_memoryの変数である”x”を利用しています。
ネストされた関数がネストしている関数の変数を使うのが、”Enclosing function’s scope“です。

Global scope“は名前の通り、グローバルなスコープなのですが、Pythonではこのグローバルの範囲が違います。
Pythonのグローバルはあくまで、”ファイル単位“です。
ファイルの内部でしか、その変数は有効になりません。
ファイルの外からその変数を使いたい場合は、importなりなんなりをしないといけない。

x = 10

def spam():
	global x
	return x

print spam()
# 10が表示される

x = 20

print spam()
# 20が表示される

“x”はソースコード内でのみ、有効です。
この他にこんなソースコードを書いても”x”は使えません。

# 先ほどのソースコードをspam.pyとする
import spam

print x
# エラーが表示される

スコープはこんなところでしょうか。
スコープ“と”関数は、やはり”Pythonは全てがオブジェクトである“ということを理解していれば、大概のコードは理解出来そうです。

ステートを保持するジェネレータ

個人的に面白いと思ったのが、”ジェネレータ“です。
これもソースコードを見た方が早いでしょう。

def spam():
	for x in 1, 2, 3, 4:
		yield x

x = spam()
print x.next()
# 1が表示される
print x.next()
# 2が表示される
print x.next()
# 3が表示される
print x.next()
# 4が表示される

print x.next()
# エラーが表示される

これは、関数の”return“の代わりに”yield“を指定することで”その時点での値を返し、関数内の処理を一時停止する“イメージです。
yield“の代わりに”return“を使ってしまうと、この関数は全て”1“を返してしまいます(一般的な関数の動作ですね)。

しかし、”yield“を使うと、”どこまで処理が進んだか“をPythonが保存しておいてくれるのです。
それを次に進ませるために”next”メソッドを呼んでいます。

処理が全て終了すると”これ以上、返す値がないよ“ということで、エラーが表示されます。

これもうまく使いこなせば色んなコードが書けそうです。

初めてのPythonにはまだまだ、たくさんのことが書いてあるのですが、とりあえず基本だけまとめてみました。
しかし、徐々に難しくなってきましたね。
以前にまとめたことをしっかり理解していないと、このあたりの動作を理解するのに苦労しそうです。

どの章でもそうですが、

Pythonはあらゆるものをオブジェクトとして扱う

これを常に念頭において読み進めるのが良さそうです。

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

初めてのPython(3) ここが違うぞ、Pythonさん

皆さんはPythonの勉強は順調に進んでいますか?
私はやっと”初めてのPython“のIII部に入れました。

タスクでは”初めてのPython”読了を1週間としていましたが、正直キツいですね。
読むだけなら良いのですが、ブログにまとめながらなのでなおさら。

しっかり読みたいしっかり理解したいのであれば”2週間“ほど掛かるかもしれません(仕事しながらなら)。

ただ、しっかり読んでも細かい部分は確実に忘れてしまうので、ポイントだけ押さえた読み方をお勧めします。
私も今、”Pythonとは何か?“に焦点を置いて、読み進めています。

初めてのPython III部

初めてのPython“のIII部には何が書かれているか?
Pythonの特徴とも言える基本構文について、がっつりと書かれています。

Pythonの特徴である”スペース“や”タブ“が意味を持つこと、少し変わった”while“と”for“。
そしてそれをどう使うか、例題を踏まえて。

さらに、”どの書き方が最もPython的で最も最適か“まで書かれているので、冒頭に述べた”Pythonとは何か?”の答えが見つけやすい。
これまでI部、II部を読みましたが、一番、”なるほど!“と腹落ちしたのがこのIII部です。

I部で全体像を理解し、II部で内部構造を理解し、III部でPythonの特徴を理解する。

初めてのPython“はこんな章立てになっています。

読み終わったら”初めてのPython 読書ガイド“を記事にしたいですね。

この記事では特徴的なPythonの構文に焦点を当て、取り上げて行きます。

Pythonとは何だ

まずはおさらいです。

以前の記事で、Pythonについて私はこう書きました(“初めてのPython“をまとめただけですが)。


Perlは芸術家のための言語、そしてPythonはエンジニアための言語。

初めてのPython(1) 基礎知識まとめ“より

Pythonはエンジニアのための言語です。
そのため、ミニマリスト主義、つまり誰が書いても同じ書き方になるように言語が作られています。

始めはぼやっとしか、この概念が理解出来ませんでした。
なるほど、誰が書いても同じように…大事だね。“程度です。
III部を読み、これがどういう意味を持つのか、少しずつ明確になってきました。

これは、

同じ種類の構文を使ったときに、様々な書き方を生まれないようにPythonが制約を作ること

だったんです。

Pythonの特徴である”インデント“もそうです。

Pythonはなぜ、”インデント“でブロックを分けるのでしょうか?
この答えも、さきほどの答えの中に含まれています。

例えば、PHPのif文はこのように書きます。

if($a == 1) {
	print 'a is one.';
	$a = 2;
}

恐らく皆さん、こういった書き方をすると思うのですが、これはこんな書き方も出来ます。

if($a == 1) {
print 'a is one.';
$a = 2;
}

こんな書き方だって出来ちゃいます。

if($a == 1) { print 'a is one.'; $a = 2; }

Pythonでは、“インデント”がブロックであり、“改行”がその文の終わりを示します。
この基本ルールに則ってやれば、先ほどのプログラムはPythonではこうなります。

if a == 1 :
	print 'a is one.'
	a = 2

“インデント”がブロックであり、”改行”がその文の終わり

これが決められてしまっているので、この書き方しか出来ないんです(もちろん例外的な書き方もありますが)。

普通、他の言語だと、こういったことはコーディング規約で決めます。
しかし、Pythonは言語自身がコーディング規約を決めています。

このように言語側でコーディング規約があれば、新しい開発メンバーが入ってきた場合も、その開発チーム”独自ルール“に悩まされなくて良さそうです。

気に入りましたよ、Pythonさん。

条件分岐

Pythonで条件分岐は、他の言語と同じく”if“を使います。

しかし、ちょっとだけ違うのが”else if“です。
Pythonでは”else if“を”elif“と書きます。

タイピングが少なくする工夫でしょう。

elif“…良いですね。

繰り返し

Pythonで繰り返しは、これも他の言語と同じ”while“と”for“を使います。

しかし、”do until“あるいは”do while“はありません
do until“がない理由も、書き方の統一のためでしょう。
全て”while”でことが足りますからね。

先ほど、他の言語と同じ”while“と”for“と言いましたが、厳密には違います。

“for”の構文がfor($i = 0; $i < 10; $i ++)ではないのです
どちらかと言うと、foreachに似ています。

Pythonではタプルやリスト、文字列などのシーケンスを使って”for“を書きます。

for x in [1, 2, 3]
	print x

じゃ、for($i = 0; $i < 10; $i ++)を書きたいときはどうするか?
range関数を使って書きます。

for x in range(0, 10):
	print x

ミニマリスト主義を徹底してますね...。

その他に面白いのは"while"と"for"に"else"が使えることでしょうか。
次のコードを両方実行してみてください。

for x in range(0, 10):
	if x == 5:
		break
else:
	print 'break is not executed.'
for x in range(0, 10):
	print x
else:
	print 'break is not executed.'

"break"文が実行されなかった場合に"else"ブロックが実行されます。
何に使うかというと、"フラグを使う必要があるとき"です。

繰り返しで何かを検索するときなど、"if"文の中にフラグと"break"文を入れますね。
これが繰り返しのelse文を使うことですっきりと書けます。

先ほどのソースをフラグを使って書いた例です。

flag = False
for x in range(0, 10):
	if x == 5:
		flag = True
		break

if flag != True:
	print 'break is not executed.'

"for"や"while"に"else"、なかなか面白い発想ですよね!

リスト内包表記

一番特徴的なのはこれです。

print [x * 2 for x in (1, 2, 3)]
# [2, 4, 6]が表示される。

リストの中に"for"を入れることで、繰り返し分のリストを作ってしまいます。
なかなか説明しにくいですが、構文的にはこうです。

[リストに入れたい値 forの構文]

なので、こんな書き方も出来ます(意味があるのかは別、教科書にはそんなソースコードがたくさん出てくるし)。

print [1 for x in (1, 2, 3)]
# [1, 1, 1]が表示される。

さらに"if"文も組み合わせて使えるようです。

print [x * 2 for x in (1, 2, 3) if x == 1 or x == 2]
# [2, 4]が表示される。

シンプルで見やすいし、理解出来れば打ちやすい。

Pythonを書くときは内包表記もがっつり使っていきましょう。
速度的にも優れているようです。
その辺りは"初めてのPython"を読んでください。
嫌というほど説明されていますから。

とりあえず、こんなところですね。
まだまだたくさん紹介したい構文があるのですが。

"初めてのPython"を参考に、"Pythonで他の言語と比べて、ここが変わっている"という点を取り上げてみました。
どうです?Pythonを使いたくなりましたか?

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

初めてのPython(2) ビルトインオブジェクトのまとめ

どんどん、Pythonを勉強して行きますよ。
今日は初めてのPython II章をまとめます。

前回の記事はこちらです。

初めてのPython II部

初めてのPythonのII部には”ビルトインオブジェクト“がまとめられています。


まず知っておかねばならないのは、Pythonではデータがオブジェクトとして扱われるということです。オブジェクトは、大きく、Python言語にあらかじめ用意されているビルトインオブジェクトと、PythonやCのツールを使ってプログラマ自らが作成するオブジェクトに分かれます。

初めてのPython“(p69)より

プログラム内でモジュールなどを何も定義することなく、利用出来るオブジェクトがビルトインオブジェクトです。
主要なビルトインオブジェクトとして、”初めてのPython“では以下のものが紹介されています。

  • 数字
  • 文字列
  • リスト
  • ディクショナリ
  • タプル

まだ、”初めてのPython“を最後まで読んでいませんが、Pythonを理解する上でこのII部が最も重要だと感じました。

始めに上記のオブジェクトの概要が、次にそのオブジェクトの詳細な説明と使用例が、最後に紹介したオブジェクトの中でも重要な部分がまとめられています。
つまり、同じオブジェクトがII部の中で3度も説明されています。
それだけ、ビルトインオブジェクトの理解が重要ということでしょう。

また、このII部を読み進めるうちに、”PHP脳を変えなければいけないな“とも感じました。
PHPPython、あまりに勝手が違いすぎる。
構文が違うだけじゃなく、このPythonの”ビルトインオブジェクト“が大きな違いを生んでいます。

II部の中では特に低水準言語であるC/C++とPythonの比較が出てきます。


ガーベージコレクションが行われるメリットは、プログラマが逐一そのためのコードを書かなくても、メモリ領域が解放されるということです。そのため、CやC++といった低水準のプログラムに比べ、プログラムの機能に直接関係のないコードをかなり減らすことが出来ます。

初めてのPython“(p123)より

こういった比較が出来るということは、Pythonがよく考えられた言語であり、様々な使い方が出来る証拠ではないでしょうか。
エンジニアがしっかりとした骨組みを考え、曖昧さを残さないように組み立てる。
それがPythonである気がします。

本文中にコード例やメソッドがいくつも出てきます。
それらを全て紹介は出来ないので、それぞれのオブジェクトの基本的な考え方をまとめてみます。

オブジェクトの基本

まず、Pythonの変数を理解します。

python_vars.png

Pythonにおいて変数はオブジェクトへのリファレンスでしかありません。
C言語で言うところのポインタのようなものですね。

これを頭に入れた上で、オブジェクトの種類を理解します。

Pythonのビルトインオブジェクトはカテゴライズされています。
そのカテゴリごとに操作が似通ってきます
これを理解すれば、かなり頭の中が整理されます。

python_object_categorize.png

まず、可変性と不変性です。

  • 可変性
    • 内容を変更出来るオブジェクト
  • 不変性
    • 内容を変更出来ないオブジェクト

簡単ですが、これだけです。
対象が”オブジェクト“であることに注意です。
先ほどの変数の説明で出てきた”リファレンス“ではありません。

例えば、”リスト“と”タプル“は同じシーケンスというカテゴリに属するのですが、可変性と不変性の点で異なっています。

# リストの例
a = [1, 2, 3]
a[0] = 10
print a
# [10, 2, 3]が表示される。[1, 2, 3]というリストの中身を変更出来る。

# タプルの例
b = (1, 2, 3)
b[0] = 10
# エラーが表示される。(1, 2, 3)というタプルの中身は変更出来ない。

# 変数の置き換え
b = a
print b
# [10, 2, 3]が表示される。エラーは表示されない。リファレンスを変えただけで、オブジェクトを変更した訳ではないため。

次に、オブジェクトのカテゴライズです。

  • 数字
    • そのまま数字です。整数や浮動小数点もこれです。
  • シーケンス
    • 簡単に言ってしまえば、配列です。連想配列ではなく、ただの配列。順序を持っています。文字列もこのシーケンスに分類されます。
  • 写像
    • こちらは連想配列です。キーに文字列などを指定出来ます。順序を持っておらず、これが保証されません。

数字は良いと思うので、問題は”シーケンス“と”写像“ですね。
どちらも配列のようなものなのですが、順序を持っているか持っていないかの違いがあります。

PHPだと連想配列でも順序を持っている(foreachで順番に参照出来る)のですが、Pythonだとそうもいかないようです。
さらに、PHPだと配列連想配列の区分は気にしなくて良いのですが、これがPythonだと明確に分けられています

# リスト(シーケンス)の例
a = [1, 2, 3]
a[10] = 10
# エラーが表示される。順序があるため、いきなり10番目の配列に代入は出来ない。代入したい場合は0...10の配列を作った後に、この操作を行う。

# ディクショナリ(写像)の例
b = {"a":1, "b":2, "c":3}
b[10] = 10
print b
# {'a':1, 'b':2, 'c':3, 10:10}が表示される。順序がないため、好きなキーに値を代入出来る。また、順序も保証されない("10:10"が先頭にいってしまうかも...)。

オブジェクトの基本はこんなところだと思います。

同じカテゴリの属するオブジェクトは基本的に同じ操作が出来る“ということも頭に入れておいてください。

あとはそれぞれの構文を覚えればOK!

数字

100

これが数字のオブジェクトです。

この他に、以下も全て数字のオブジェクトです。

  • 10.00010
  • 11111111111111111111111111111111111L
  • 0x9ff
  • 3+4j

Pythonでは以下の数字が使えます。

  • 短整数
    • 1234, -24, 0
  • 長整数
    • 1111111111111111111111111111L
  • 8進数, 16進数
    • 0177, 0x9ff, 0XAA
  • 複素数
    • 3+4j, 3.0+4.0j, 3J

中の処理を説明しだすと、長いので(そしてさほど理解出来ていないので)省略します。
数字に関しては、一般的なスクリプト言語と同じように使えそうです。

数字は不変性のオブジェクトなので、変更出来ません(というか数字を書き換えるような操作って出来ないよね、きっと)。

文字列

‘Spam’

これが文字列のオブジェクトです。
書き方は他のスクリプトと一緒でも、Pythonはひと味違います。

print 'Spam'[1:3]
# "pa"が表示される。

こんなことが出来ちゃいます。

Pythonにおいて文字列はシーケンスに属します。
シーケンスは順序を持った配列なので、スライシング(特定の部分だけ取り出す)インデキシング(一つだけ取り出す)が可能です。

今回、行ったのはスライシングです。
2〜3文字目の文字を取り出して、表示してみました。

文字列のオブジェクトをUnicodeで扱うことも、文字列のオブジェクトの先頭にuをつけることで指定できます。
その上でスライシングも期待通り動作します

print u'こんにちは'[1:4]
# "んにち"が表示される。

mb_hogehoge()要らず“ですね。

文字列は不変性のオブジェクトです。
以下のような変更は出来ないので注意。

a = 'test'
a[0] = 'b'
# エラーが表示される。

文字列は便利なメソッドを色々持っています。
例えば文字列を置き換えるメソッド。

a = 'This is test.'
print a.replace('test', 'cat')
# This is cat.が表示される。
print a
# This is test.が表示される。'This is test.'のオブジェクトが書き変わった訳ではない。

これも’This is test.’の文字列オブジェクトが書き変わった訳ではないので注意が必要です。
‘This is test.’を書き換え、‘This is cat.’という新しい文字列オブジェクトをPythonは生成したのです

文字列はこれらが基本だと思います。

文字列のオブジェクトは”シーケンス“カテゴリで”不変性“であること。
これを覚えておくとばっちりです。

リスト

[1, 2, 3]

これがリストです。

リストは”配列“と考えて良いと思います。
リストの値にアクセスするには以下のコードを使います。

print [1, 2, 3][2]
# 3が表示される。
a = [1, 2, 3]
a[0] = 10
print a
# [10, 2, 3]が表示される。

もちろん、入れ子にも出来ます。

print [1, 2, [3, 4, 5]][2]
# [3, 4, 5]が表示される。
a = [1, 2, [3, 4, 5]]
a[2][0] = 10
print a
# [10, 2, [10, 4, 5]]が表示される。

リストは”シーケンス“カテゴリに属します。
文字列と同じく、スライシングやインデキシングの操作が出来ます。

print [1, 2, [3, 4, 5]][1:3]
# [2, [3, 4, 5]]が表示される。

リストは”可変性“です。
オブジェクトに対して変更を加えることが出来ます。
appendやpop、removeといったメソッドを持っており、オブジェクトに対してこれらの操作を実施します。

a = [1, 2, 3]

a.append(4)
print a
# [1, 2, 3, 4]が表示される。

a.remove(1)
print a
# [2, 3, 4]が表示される。

a.pop()
print a
# [2, 3]が表示される。

print a.append(5)
# [2, 3, 5]ではなく、Noneが表示される。元々存在するオブジェクトに対する操作のため、返り値は、他の言語のNULLに相当するNoneが返る。

リストのオブジェクトは”シーケンス“カテゴリで”可変性“です。
文字列のオブジェクトと比較してみてください。
それで、さらに理解が深まるかと。

ディクショナリ

{‘cat’:'neko’, ‘dog’:'inu’, ‘spam’:'unknown’}

これがディクショナリです。

ディクショナリは”写像“というカテゴリに属するため、リストや文字列とは操作が異なります
例えば、リストや文字列で行ったスライシングの操作をディクショナリで行うとエラーが表示されます。

{'cat':'neko', 'dog':'inu', 'spam':'unknown'}[1:3]
# エラーが表示される。

{'cat':'neko', 'dog':'inu', 'spam':'unknown'}['cat':'dog']
# エラーが表示される。

逆にリストでは出来なかった操作が出来ます。
文字列キーの使用と、存在しないキーへの代入です。

print {'cat':'neko', 'dog':'inu', 'spam':'unknown'}['cat']
# nekoが表示される。

a = {'cat':'neko', 'dog':'inu', 'spam':'unknown'}
a['new'] = 'atarashii'
print a
# {'new': 'atarashii', 'spam': 'unknown', 'dog': 'inu', 'cat': 'neko'}が表示される。

リストと同じく、ディクショナリも”可変性“のオブジェクトなので、オブジェクトに対して代入が出来ています。

さらに”不変性“のオブジェクトであればどんなものでも、ディクショナリのキーに設定出来ます。
例えば、タプルをキーに設定出来ます。

print {(1, 2, 3):'tuple', 'dog':'inu', 'spam':'unknown'}[(1, 2, 3)]
# tupleが表示される。

かなり複雑な構成もディクショナリとタプルの組み合わせで実現出来そうですね。

ディクショナリのメソッドとして、PHPのarray_keys()にあたるkeys()や、array_values()にあたるvalues()があります。
また、PHPではキーチェックはisset()で行うのですが、Pythonではディクショナリに対してhasKey()メソッドが使うことで実現出来ます。

ディクショナリだけ、リストや文字列とちょっと違う”可変性”のオブジェクトだと覚えておくと良いかもしれません。

タプル

(1, 2, 3)

これがタプルです。

タプルは”シーケンス“カテゴリに属する”不変性“のオブジェクトです。
ここまでしっかり理解出来た方であれば、何が出来るか想像出来ると思います。

ソースコードの例だけ書いておくので、後は省略させてください。

a = (1, 2, 3)
a[0] = 10
# エラーが表示される。

print (1, 2, 3)[0]
# 1が表示される。

print (1, 2, 3)[1:3]
# (2, 3)が表示される。

ビルトインオブジェクトはこんなところですね。
初めてのPythonにはもっとたくさんのことが書いてあるのですが、基礎中の基礎をまとめてみました。

Pythonのチュートリアルが終わったらもう一度、II部を読まないとダメかな。

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

初めてのPython(1) 基礎知識のまとめ

learning_python.jpg

なんだか、前回の記事はお喜び頂けたようで何よりです。

あれは本当に自分のために書いたので、あんなに皆が読んでくれるとは思っていませんでした。
皆、Pythonの勉強が進まなくて困っているんですね(苦笑)

言い出しっぺが書きっぱなしというのもあれなので、しばらくブログをPythonの勉強記事を上げて行きます。

今日は“初めてのPython”のI部のまとめです。
初めてのPythonなんて読む時間がないよ!“という方は、記事を読んでエッセンスだけ抜き取っちゃってください。

初めてのPython I部

初めてのPythonのI部には、Pythonの基礎知識がまとめられています。
Pythonがどんな言語なのかどういったものが作れるか開発環境は何を使うか、そしてPythonのバッググラウンドまで。

Linuxだけでなく、Windowsでの開発環境の構築の仕方まで載っていました。
ただ、自分はLinuxユーザなのでWindowsはスルー。

初めてのPython“に載っていたことに、自分で調べたことをプラスαして以下にまとめていきます。

Pythonのコンセプト

Python Fits Your Brain.
(2001年のPythonカンファレンスのテーマです)

これがPythonのコンセプトの一つのようです。
つまり、あなたの脳にぴったりなプログラミング言語を。

Pythonは構文がシンプルで明瞭です。
それは、誰が読んでも、理解しやすくメンテナンスしやすいということです。

初めてのPython“にはPerlとPythonを比較した上で、こういった表現がありました。

Pythonプログラマは、あくまで「アーチスト」ではなく、優れた「エンジニア」であるべきでしょう。

初めてのPython“(p16)より

初めてのPython“を読んで、気に入った表現の一つです。

Perlは芸術家のための言語、そしてPythonはエンジニアための言語

初めてのPython“にあるのですが、Perlは優れた言語学者によって開発されました。
それゆえ、Perlはプログラマーによっていく通りもの表現が書けるようになっています。

それに対し、Pythonは優れた数学者によって開発されました。
それゆえ、Pythonはプログラマーによって出来るだけ解が一つになるようになっています。

芸術家は人により様々な表現があって良い。
しかし、エンジニアは強固な物を作り上げるために、そうはいかない。
出来るだけ、皆にわかりやすい形にする義務がある。

ということでしょう。

良い設計思想だと思います。
私が”Pythonを勉強したい”と思う一つの理由でもあります。

しかし、これを読むと”Pythonが素晴らしい”と思うと同時に、Perlも勉強したくなるんですけどね(笑)

Pythonで作れるもの

何でも作れます。

これが”初めてのPython“から得た私の印象です。

Webアプリケーションから、シェル、GUIのアプリケーションそして大規模な科学まで。
Pythonがオブジェクト指向として設計されていること、そして他言語とフレンドリーな形で実装されていることが、大きいのだと思います。

初めてのPython“には、Pythonにはこんなことも出来るとありました。

フローズンバイナリとは、前章で触れたとおり、PythonプログラムのバイトコードとPythonインタプリタを1つの実行形式ファイルにまとめたものです。他の実行形式ファイルと同様、アイコンをクリックする、コマンドラインで名前を入力する、といった方法で起動出来ます。

初めてのPython“(p59)より

Pythonがオブジェクト指向言語であることは、コードの作成、再利用に役立つだけでなく、C++、Javaなどの他のオブジェクト指向言語のプログラムと組み合わせて使うスクリプトの作成に役立ちます。たとえば、適切なグルーコードを使えば、Pythonで、C++やJava、C#のクラスを継承(特殊化)するプログラムを作ることも可能です。

初めてのPython“(p12)より

2つ目は特に試してみたいですね。
私はC++も勉強し、習得したいと思っています。
Pythonを習得する過程で、C++も習得出来れば素晴らしいですね。

もちろん、スクリプト言語の十八番、(動的に生成した文字列をコードとして扱う) eval()も使えます。

動作速度とコード量

うまく書けば、コード量はC++やJavaの1/3〜1/5程度になるようです。

そして、以下の仕組みを取り入れることで、他のスクリプト言語より高速に動作するようです。

python_execute.png

一度、Pythonコードを実行すると、.pycの拡張子のバイトコードが作られます。
このバイトコードはソースコードと機械語の中間コードで、元のソースコードを高速化します。
実行時はこのバイトコードをランタイムに渡し、実行します。

二回目以降の実行はこのバイトコードへの変換がなくなるため、起動が高速化します。

また、こんなツールもあるようで。

このような高速化の仕組みもPythonの魅力の一つではないでしょうか?

開発する上で気をつけること

読んでいて気がついた”開発する上で気をつけること“をまとめます。

  • ターミナル上で対話型でプログラムを実行するときは、Pythonコードの特徴である”タブ”が不要
  • 同様にターミナル上で対話型でプログラムを実行するときは、printも不要
  • シェルを作るときに拡張子.pyをなくても実行出来るが、モジュールには.pyが必要

全てターミナル上でPythonを実行するときの注意ですね。

開発環境

私はエディタはvi、ターミナル上でほとんどのことを済ませるので、IDEは不要です。
しかし、”初めてのPython“には以下のようなPython開発用のIDEが紹介されていました。

  • IDLE
    • 初めてのPython“で細かく紹介されています。Eclipseのように高機能ではありませんが、必要な機能は十分に備えているようです。初心者にもお勧め、とあります。
  • EclipseとPyDev
    • 言わずと知れたEclipse、そのPython拡張がPyDevです。
  • Komodo
    • 有償のIDEですね。GUIのデザインも出来るようです。
  • PythonWin
    • Windows用のPythonのIDEですね。機能的にはIDLEと同じと書かれています。

私は使うことはないと思いますが、まとめだけ。

ユーモア

コメディ番組 “空飛ぶモンティ・パイソン”

このパイソンからPythonは来ています。
イギリスのコメディグループ”モンティ・パイソン“が出演する番組です。

空飛ぶモンティ・パイソン (Monty Python’s Flying Circus) は、1969年から1974年までイギリスのテレビ局 BBC が製作・放送したコメディ番組である。文字通り、イギリスのコメディグループモンティ・パイソンが出演していた。
同時代事件や哲学に敏感に反応するとともに、同性愛や民族・宗教上の差異を扱ったきわどいネタも多く、そのナンセンスさと毒の強さは以後コメディにとどまらず多くの欧米文化に影響を与えた。特に本国イギリスではコメディ番組の時代毎の傾向を(それ以前にもそれ以降にも様々なコメディ番組を輩出したにも拘らず)「Pre-Python(パイソン放送以前-1969年以前)」「On-Python(パイソン放送当時-1969年〜1974年)」「Post-Python(パイソン放送以後ー1975年以降)」とカテゴライズするところからも如何にこの番組が英国コメディ番組史に多大な影響と衝撃を与えたかが読み取れる。また、BBCが公共放送であるにもかかわらず、エリザベス女王の映像をコントに使うこともあった。

空飛ぶモンティ・パイソン – Wikipediaより

サンプルコードに一般的な”foo”や”bar”の代わりに、”spam“や”eggs“が使われるようです。
それはこの”空飛ぶモンティ・パイソン”のネタから来ているとのこと。

Pythonには関係ありませんが、”スパム・メール“のスパムもこの”空飛ぶモンティ・パイソン“から来ているそうですよ!

こういうユーモアはツールを使うのを楽しくしてくれますよね。
自分も何か、サービスやツールにユーモラスなネーミングをしたいなぁ。

ざっとですが、”初めてのPython“のI部をまとめてみました。
自分の必要なところだけを抜き出してあります。

本は人によって必要となるところが違うので、これを読むだけで満足しないでください
初めてのPython“はすごく内容の濃い本なので、是非、一緒に読んでいきましょう。

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

ホーム > タグ > プログラミング言語

スポンサードリンク
書いている人
つぶやき
  • setup.pyのinstall_requiresにgitのリポジトリを指定したい。どうすればいいかな。 1 day ago
  • ツイッタークライアントを久々に開いたけど、なんか違和感。 3 days ago
  • 最近、イベント参加出来てないな(_ _) 3 days ago
  • More updates...
RSS 気になるニュース
過去の記事

ページの上部に戻る