2010年9月1日水曜日

変数とか関数とかメソッドとかコンストラクタとか

プログラムが初めて、というひとには耳慣れない言葉が多数出てきました。
ここらで、それらの用語を解説しておこうかと思います。
ちなみに。これらの用語は、たいていの手続き型言語、或いはプログラム言語で、ほぼ共通の用語なので、覚えておいて損はないんじゃないかな、と思います。
まあそれと、厳密な意味とか、そういうのは、もっとまっとうなドキュメントを参照してもらうことにして、ここでは「ああ、そんなものなのだな」というイメージだけつかんでもらえればいいかな、と思ってます。
というわけで、簡単に適当に説明しますので、身構える必要はありません。おっさんは、「なんとなく」解ってればいいと思うんですよ。(笑)

変数とか


変数ってのは何かってぇと。単になんかを入れるポケットと思ってもらえばいいです。
Pythonの場合には、このポケットには、なんでも入れられるので、本当に柔軟な入れ物である、と言えます。
本当になんでも入ります。(笑)
#C言語系だと、入れ物の「型」が決まってたりして、非常に面倒。
イメージとしては「ドラえもんの四次元ポケット」をイメージしてもらえばいいでしょうか。そのくらい何でも入るんです。Pythonの変数は。(笑)
ポケットには、名前が付いていて、Pythonの場合には、名前を付けて「中身」を入れた時点で有効になります。現時点でのサンプルコードだと、以下のような書き方でしょうか。
self.gladefile = "mikunchu.ui"
gladefileという「変数」に”mikunch.ui”という文字列(中身)を入れています。
#代入という言い方を良くします。
#ちなみに、”や'、''' で括られた文字を「文字列」といいます。詳しくはこの辺を参照。(笑)
以降、gladefileの中身が”mikunch.ui”であるよ、と宣言した、ってことですね。変数というのは、その名のごとく、変わる数、なので、後から中身を入れ替えることも可能です。
まだサンプルでは、そういう使い方をしている部分はありませんね。
なお、変数の前にself.とついていますが、これは変数のスコープ、有効範囲を示しているのですが、これは後述します。
#てか、変数のスコープは、実は結構重要な話で。

変数の使い途


変数がポケットであることは「なんとなく」解ったかと思いますし、そもそもポケットなんで、何かを入れとくんだろうな、って想像も付くかと思います。
でも、ビスケット入れて叩いても、割れて二つになったりしないので、そこは注意が必要です。
じゃあ、変数ってどんな時に使うんでしょうね、ってのがイマイチ先の説明では汎用的ではないかな、ってことで、ちょいと補足しようかと思います。

変数には、大きく二つの使い方があって、先に説明した「値を保持しておく」役割が、一番大きいのですが、もうひとつ、一時的な値の保持ってのもあります。
これは後で説明するスコープにも重要な関わりがあるんですが、例えば、計算の結果を、後で使う場合には、その結果を保持しておく必要があります。
普通はメモ書きなんかして、電卓弾いた結果を残しておきますが、これが一時的な値の保持、結果として、旅費の精算なんかするときに、書類に書いて出しますが、その旅費精算の金額が、恒久的な値の保持、スコープの関係は後述するとして、自分のメモ書きは、自分で何度も書き換えて使うので、まあ、何を書いても結果さえ合ってれば構わないし、使い終わったら捨てる、ってのが変数の使い途だったりします。
一方で、旅費精算の結果は、総務に提出しないとならないので、総務が参照できるところに書いておきます。で、こういう総務が参照できるような、みんなが見るような場所に書いとくものは、頻繁に書き換えたりすると、参照する方も面倒なので、なるべく、最終的な結果だけ書いとくようにしとくべきです。

まあ、メモ書きには、オヤジギャグのネタをメモして、ダメだったら捨てる、とかもあると思いますが、プログラム的な変数の使い途は、このようにメモ書きとして使用する場合がほとんどとなります。
メモ書きなんで、追記も出来るし、消して書き直しも出来る。
その上、ドラえもんの4次元ポケットなので、なんでも入るし。音声メモと、手書きメモが混在出来ると思ってもらえばいいでしょうかね。
普通有り得ないから、イメージしにくいと思いますけど。
あ、絵も描けるし、字も書けるくらいなら、イメージしやすいですかね。(笑)
あとで使うものは、基本的に変数に格納、ってことが鉄則ってことでしょうか。
コンピュータってのは、こうして、メモを残しておかないと、何もかも、次の瞬間にはキレイサッパリ忘れてくれるので、後で使うものは、このように明示的にメモを残してあげないとダメなのです。

そういう意味ではおっさんより質が悪いですね、おっさんは、大体三歩ぐらいは覚えているので。

変数のスコープ(有効範囲)


変数にはスコープ(有効範囲)ってのがあります。
まあ、ある意味、賞味期限と思ってもらってれば間違いないんですが。
賞味期限が過ぎると、喰えなくなるように、変数も参照できなくなります。
大きく分けると、グローバル、クラス、ローカルの三種類になるんですが、以下の特徴ですかね。

  • グローバル 賞味期限がなく、どこからでも参照できる。
  • クラス クラス内でのみ使える。selfがついてるのは、これ。
  • ローカル 宣言した関数内でのみ使える

グローバル変数は、あまり使わないし、共通設定とか、参照のみの場合が多いので、あまり気にしなくてもよいですし、乱用はキケンなので、極力使わない、という考えでいてください。
とはいえ、グローバルが有効な場面もありますので、そういう場合には使用を制限するものではありません。
例えば、さっきの例で言えば、総務に旅費精算を通知する場合ですかね。
ここに書いといたから見といてよ、と総務に連絡しとくと、グローバル変数であれば、総務も自分も参照できる、というわけです。
#ま、仮に実際に、本当にそういうプログラム書いたとして、グローバル変数にそんなの格納しちゃダメですけどね。
単に、グローバル変数の多用はプログラムの見通しと、デバッグを大変にする、または、意図しない代入が行われて、意図しない動作をするバグの温床になりやすいので使用は注意って話です。
#総務が確認する前に、他のひとの旅費精算の金額で上書きされちゃうとか、そんな悲惨な結果になります。高いんなら問題ないかも知れませんが、安くなったりすると悲惨ですよね。

変数ではなく、設定値を保持するとか、基本的にアプリケーション実行中は書き換えないような値の保持に使用する分には便利なので、そういう使い方を推奨します。
例えば、アプリケーション起動直後の初期化で、値を設定してしまって、以後は参照のみ、とかいう使い方ですね。

クラススコープの変数は、self.を変数の名前の前につけて宣言し代入します。
前述したサンプルコードがクラススコープになってますね。
でも考えてみれば、前述の変数はクラススコープになってる必要がないので、なんでself付けてるんでしょうね。あとで修正しておきましょうか。(笑)

クラススコープの変数は、そのクラスの中でだけ使えるポケットということになります。
ちと、PCヲタクっぽい例えで行けば、グローバルスコープは、インターネットに公開されたサーバ、と思ってもらえばよいでしょうか。
一方で、クラススコープは、家庭内サーバと考えると解り易いかも知れません。
家庭内に複数のPCがある場合には、どのPCからでも、その家庭内サーバにはアクセスできます。もちろん、インターネットに公開されたサーバにもアクセスできます。
でも、他のご家庭の家庭内サーバにはアクセスできませんよね。
この場合、インターネットがグローバルスコープ、各々のご家庭がクラス、家庭内サーバがクラススコープと考えればわかり易いのではないか、と思うのですが。
そう、ここまでくれば、ローカルは、個々のPCがスコープ、ということが想像が付くと思われます。(笑)

なにも付けずに変数名だけを書いた場合には、基本的にローカルスコープとなって、その関数内でしか参照も代入も出来ない変数となります。
前述の例だと、共有されていない個々のPC内のファイルとでも考えてもらえばイメージが付きやすいでしょうか。
例を書き直すと、ローカルスコープで変数を使用する場合には、以下のようになります。
gladefile = "mikunchu.ui"
self.がなくなっただけ。(笑)
結果として、__init__(self)関数の外からは、gladefileという名前の変数を参照しようとしても、新たに作られた同名のローカル変数として扱われてしまい、代入された"mikunchu.ui"は参照できません。
個々のPCに、hoge.txtというファイルがあったとして、中身が一緒じゃないのと同じことです。
ワタクシの「ひみつ」フォルダの中身と、あなたの「ひみつ」フォルダの中身は、異なりますよね?
#たぶん、異なると思うんだ。
ローカルスコープというのは、そういうことです。

まあ、ぼんやりと「スコープ」に関して、解って貰えたんじゃないかと思います。
実際に、「理解する」のは、痛い目を見てからじゃないと、なかなか実感できないので、実際に自分でオリジナルプログラムを作ったときに、何度も痛い目を見て、身に付けてください。(笑)
なお、Pythonのスコープの詳細はここに書いてありますね。
#まあ、別に見なくてもいいと思いますけど。

スコープの使い分けはどうしたもんでしょうね


基本的に、アプリケーション全体で参照するものをグローバルなスコープとする、ってのは簡単に想像が付くと思いますが。
ローカルスコープとクラススコープの使い分けは、ってえと、少し悩ましいかも知れません。
とはいえ、先程のPCヲタクっぽい例で言えば、ちょっとはわかり易いかも。
ってことで。
例えば、自分のPCだけに秘蔵しているエロ動画は、他のPCから見られたら困るわけです。
#というか、他のひとに見られては困る。
一方で、家族旅行に行った時の動画や写真、そして録画したTV番組などは、家族で共有したい。
つまり、エロ動画はローカルスコープに置き、家族で共有したい動画はクラススコープに置く、と考えれば、少し、スコープの考え方がわかり易くなるのではないでしょうか。

他に見られたくないもの、あるいは使い捨てのものは、ローカルスコープに。
少なくとも、そのクラス内では共有したいものはクラススコープで宣言するとよいでしょう。
まあ、変数のスコープは、実際に使う段にならないと、どのスコープがいいか、なんて解りにくいものですが、そんなイメージで使い分けられれば、まずは十分じゃないでしょうかね。

関数ってなんぞ?


関数。函数なんて書いた時代もあったようで。
基本的に。
関数というのは、「何か入力されるとアクションを起こす箱」です。
いわば、びっくり箱、でしょうか。
開くと中からびよよ〜ん、となんか出てきて、ひとを驚かす。
この場合、「開く」という入力があり「中から何か飛び出す」というアクションがあるわけです。

んで、Python風にびっくり箱を定義するなら、以下のようになるかと思います。
#実際に動くコードではないので、誤解のなきよう。

def びっくり箱(開く):
    中から人形が飛び出す
そのアクションが、計算して値を返すことだったり、画像を表示することだったり、動画を再生することだったりするだけで、基本的な考え方は、上記のものです。
入力に対して、なんらかのアクションを起こすものが関数なのです。

では、メソッドとの違いは何か?
えー、ぶっちゃけ同じです。(笑)
入力を受けて、アクションを起こす、これは関数でもメソッドでも違いはありません。
何が違うか、といえば、関数は独立してアクションを起こすものであり、スコープで言えば、グローバルなスコープに属するものです。

一方で、メソッドはクラスに属するもので、入力を受けてアクションを起こすのは同じですが、「属するクラスに対して」アクションを起こすもの、と言えるかと思います。
クラスに対してアクションを起こす「手段」なので「メソッド」なのですね。
ま、この辺の細かいところは「へー」ですませても問題ありませんので、まあ、そういうものなんだな、くらいで終わらせといていいかと思います。(笑)

なお、やっぱり関数に関しての詳しい説明はここにあります。(笑)

関数の使い途


関数とか、メソッドは、どんな場合に使うのか、どんな使い途があるのか、ってのを、ちと説明しておきましょうか。
プログラムなので、なんらかのアクションがないと成立しないので、この後で出てくるシグナルハンドラなどは、メソッドとして使われます。
ユーザーの入力(操作)に対してのアクションという形ですね。

その他、プログラムでは、基本的には「同じことを2度書かない」という鉄則があります。
#まあ、鉄則ちゅうか、知恵っちゅうか。
そういう場合には、同じ部分を切り出して、関数にするなり、ローカルなメソッドにするなりして、記述するのです。
そのようにすることで、全体の見通しを良くし、かつ、同じ処理は同じ関数を使用することで、間違いを減らす、手間を減らす、バグを減らす、ということが可能になります。
#ま、この辺は、ちと中級というか、テクニック的な話なので、さほど重要じゃないかも知れませんが。

いずれにせよ、GUIプログラミングでは、確実にシグナル(イベント)に対しては、対応するメソッドが必要になります。メソッドの使い途として、最も重要な使い途になります。
また、これらの「処理」というのは、結局のところコンピュータに「このような処理をせよ」と指示を出す部分でもあります。
つまり、関数やメソッドの使い途というのは、「コンピュータに指示を与えるため」に使うのです。
呼び出しタイミングや、分割の仕方などは、様々ですが、使い途としては、このためです。
プログラミング言語で、関数、メソッドというのは、実質的な処理のことなのです。
コンピュータは、バカなので、指示されなければ、何も出来ませんし、また、指示された通りに実行します。
事務のあのコのように、間違えているアナタの書類を、そっと修正してくれたりはしないのです。
日頃から、事務のあのコに出張のお土産を買ってきてたりすれば、気を利かせて、間違いの訂正なんかもやってくれるものですが、コンピュータには、いくら気を使っても、気を利かせてくれるなんてことはありません。実直に、そして素直に指示されたことだけを行います。
その指示を行うのがメソッドであり、関数なのですね。
で、バグを作りこむのも、大抵はコンピュータではなく、アナタの責任です。(笑)

コンストラクタって何?何のために使うもの?


また、コンストラクタという言葉も出てきました。
これは何か、というと、やはり関数、メソッドの一種です。
ちと特殊な用途と言えば特殊な用途ですが、まあ、関数には違いありません。
どこが特殊かというと。
先程説明した「入力」の部分が特殊といえるかも知れません。
#まあ、実際には呼び出されるタイミングなんだけど。
コンストラクタというのは、クラスが実体化されるときに、一度だけ呼び出されます。
そのため、クラスの各種初期化を行うメソッドと考えればよいかと思います。
#一度だけ、というのは、実体化するときに一度、なので複数実体を持つような場合には、その度に呼び出されます。
なんつぅんですかね、こう、そのクラスに対して、「今からお前を使うから、ココロの準備をしておけ!」みたいな感じで呼び出されるってところですかね。
手のひらにひとという字を書いて飲み込むひともいるでしょうし、観客はかぼちゃだ、と思い込むひともいるかも知れませんが、コンストラクタの役割とは、そのようなものです。
そのクラスを、「実際に使うときに必要な初期化を行う」ためのメソッドなのです。

サンプルコードにも__init__(self):というなんか如何にも特殊そうな書き方がされていましたよね?
これはPythonの決まりで、コンストラクタはこう書く、と決まっているのです。
#いわゆる仕様ってやつです。

他にも、特殊なメソッドはいくつかありますが、まあ、まずはコンストラクタだけ知ってれば、そんなに困りません。てか、少なくともワタクシは困ってません。(笑)

というわけで、今まで出てきた専門用語は、大体説明したかな?
まあ詳細はそれなりのドキュメントを参照してもらえばいいと思うんですが、おっさんですので、「なんとなくこんな感じ」さえイメージできれば、まずは十分じゃないのかな、とワタクシは思います。(笑)

1 件のコメント:

  1. おっさん、ありがとうー!
    今までのモヤモヤが取れた!!!
    おっさより。

    返信削除