フタミノブログ

マーケティングから技術まで色々

Pythonチュートリアルをやってみる その6

f:id:nimi0370376:20170716142105p:plain

 

少し間が空いてしまったが、続きをやっていく。

前回は、確かpythonの入出力についてやった気がする。さほど難しくなかったし、Rubyにも共通する表現だったので問題なかった。

前回のエントリは下記リンクからご覧いただきたい。

nimi0370376.hatenablog.com

 

前回のエントリが短かったのもあって、今回は2章続けて紹介していく。

正確に言うと1.5章なのだが。

まずは、エラーについてやっていく。pythonではどのようなエラーが表示されてどのように応用できるかを見ていく。そのあとにクラスについてやっていく。rubyにもあってクラスはpythonにもある。

クラスは継承の手前までやっていく。

 

 

第8章 エラーと例外

Pythonのエラーには、2種類ある。一つは構文エラー(syntax error)。もう一つは例外(exception)といわれるものだ。

 

構文エラーはさらっと流せるのだが、例外は少し長い。

 

8-1 構文エラー

構文エラーは、Pythonを勉強していく中でよく怒られるやつ。文法間違ってるよーってやつ。

f:id:nimi0370376:20170716142940p:plain

例えば、こんなやつだ。必要なコロン[:]がないから怒られる。

 

8-2 例外

例外と言う奴も見ていく。例外自体は難しくない。

f:id:nimi0370376:20170716143154p:plain

 

1を0で割るなと言われている。当たり前の話だ。例外エラーの検知は自分自身にあると言える。最もPythonは間違えてないけど、どう頑張っても計算できないよと言うことだ。

 

8-3 例外の処理

プログラムは、選択した例外を処理するように書くことができる。例えば下記のようにできる。

 

f:id:nimi0370376:20170716143808p:plain

 

try文は、次のように動作する。

  • 最初にtry節(tryとexceptに挟まれた文)が実行される。
  • 例外が送出されなければexcept節はスキップされ、try文の実行が終了する。
  • try節実行中に例外が発生すると、try節中の残りはスキップされる。発生した例外の肩がexceptキーワードの後ろで指定してある例外と一致すればexcept節が実行される。

また、tryやexceptは一つだけでなく、何個も設定できる。それが下記のプログラムになる。

 

f:id:nimi0370376:20170716144919p:plain

 

8-5 例外の送出

プログラマは、例外を強制的に送出することができる。ここで鍵になるのはraise文である。

 

f:id:nimi0370376:20170716145153p:plain

 

raiseの唯一の引数は送出例外を示すものである。

f:id:nimi0370376:20170716145416p:plain

 

他にもfinally文などがあるのだが、ブログで紹介するのはここまでにしておきたい。

 

第9章 クラス(前半)

さて、次がクラスの説明になる。クラスは非常に大事な概念が詰まっているし、適当にやりたくないので2つに分けてゆっくり説明しようと思う。

今回は、Pythonのクラスがどんなものなのかと言うことから、インスタンス変数とクラス変数について紹介していく。

 

9-0 クラスについて

Pythonのクラスについてだが、一言で言うと拡張可能である。C++などとは異なり、ビルトイン型を基底クラスとしてユーザーが拡張を行うことができるのだ。のちにやるが、クラス継承もラクラクできる。一方でクラスは継承時にオーバーライドされる危険性があるので、十分に注意する必要がある。

 

オブジェクトには、個体性があり、同じオブジェクトに複数の名前が(複数のスコープで)結合できる。基本的な変更不能型(数値、文字列、タプル)を扱う時には無視して構わない。ただし、たまにこの概念を忘れて大変なことを招くことがある。その例はのちに見ていく。

 

9-1 Pythonのスコープと名前空間について

クラス定義では、名前空間で遊ぶので、何がおきているかをちゃんと理解するには、スコープと名前空間の動作を知っておく必要があるのだ。

 

例えば、z.realと描いた時、realはオブジェクトzの属性である。厳密に言うと、モジュール内の名前に対する参照とは、属性の参照である。つまり、mod_name.funcnameと書いた時、mod_nameはモジュールオブジェクトであり、funcnameはその属性となる。

 

名前空間は、様々なタイミングで作られ、寿命も様々である。ビルトイン名の入った名前空間は、Pythonインタープリタの起動と共に作られ、終了まで削除されないのだ。

 

また、スコープは、ある名前空間から直接アクセスできる、プログラムテキスト状の範囲のことである。スコープは静的に決定されるものだが、利用は動的に行われる。スコープは下記のような性質を持つ。

 

  • 最も内側にあり、最初に検索されるのはローカル名の入ったスコープである。
  • これを取り囲む関数がある場合、その名前空間も最内のスコープから順に検索される。ここには非ローカル、非グローバルな名前が入っている。
  • 最初から2番目に検索されるスコープには、今いるモジュールのグローバルな名前が入っている。
  • 最も外側のスコープは、ビルトイン名の入った名前空間である。

 

9-2 スコープと名前空間の例

実際にスコープと名前空間を見た方が早いと思うので、実際にお見せする。

f:id:nimi0370376:20170716151249p:plain

 

上記の出力は、こうなる

f:id:nimi0370376:20170716151411p:plain

 

ローカル代入はscope_test内でのspamのバイディングを変化させない。nonlocal代入は、scope_testのspamバインディングを変更し、global代入は、モジュールレベルでのバインディングを変更する。つまり、(global >= nonlocal >>local)みたいになる。

 

9-3 はじめてのクラス

クラスの一番簡単な形は下記のようになる。

class ClassName:

   <文1>

    :

    :

 <文N>

 

9-3-1 クラスオブジェクト

クラスオブジェクトには、様々な機能がある。属性参照は全く普通の構文で行われる。obj.nameの形式だ。クラス定義が下記のようになっている場合。

 

 

f:id:nimi0370376:20170716152438p:plain

 

この場合、MyClass.iとMyClass.fとして属性参照することができる。

また、

         x = MyClass( )

として変数に代入もできる。

 

9-3-2 クラス変数とインスタンス変数

二つのプログラムと出力を見て欲しい。

f:id:nimi0370376:20170716152903p:plain

出力:

canine

canine

Fibo

Buddy

 

まず、Dogクラスと言う空間内に犬に名前をつけていくことにする。

一匹ずつ決めるのが面倒だから最初は、共通してcanineと呼ぶことにした(kind)。でもやっぱり犬がかわいそうだから一匹ずつ名前をつけることにした。だけど最初にcanineと名付けてしまった。そこでkindと呼んだ時にはcanineとして反応して欲しい。nameと呼んだ時にはそれぞれの名前を教えて欲しい。それが上記のプログラム

 

一方下記は、

f:id:nimi0370376:20170716153311p:plain

出力:

canine
canine
Fibo
Buddy
['転がる']

 

違うのは、self.tricks =の場所だ。

Catクラスで、からのtricksを用意してあげる。次にadd_trickでtricksにどんどん単語を入れてあげている。

 

これがもし下記の場合...

 

f:id:nimi0370376:20170716153810p:plain

 

先に共通してと呼ぶことにしている。そのあとにどんどん単語を入れているのだ。出力は下記のようになる。

 

canine
canine
Fibo
Buddy
['転がる', '死んだふり']

 

一緒に呼ばれしまうのだ。eもdも関係なく。