トップページ | Python 標準ドキュメント | 事例集 | アーティクル | リンク集 | ダウンロード | サイトマップ 
468x60サイズバナー・シリーズC Simple Fun and Indented
コンテンツ
Pythonの紹介 - プログラミング経験のない人に
Instant Python - Python入門
Instant Hacking - プログラミング経験のない人に
Top
 
Python Powered
Powered by Zope
PyJUG網元衆










インスタント・ハッキング

Magnus Lie Hetland 
translated by jack_dul@mx13.freecom.ne.jp



これは、プログラミング入門用の短い文章です。プログラムの実例はPython言 語によって書かれています。(もしあなたが既にプログラミング経験者であり、 Pythonについてのみ知りたいのなら、私 のinstantPython という記事を御覧下さい。)この記事は既に イタリア語ポー ランド語、日本語に訳されており、現在、韓国語に翻訳する作業が進行中 です。


このページは、どうやって他人のコンピューターに侵入するかなどについて書 かれているのではありません。私はその手のことに詳しくなんてないのでメー ルを送ってこないで下さい。ハッキングとは何のことなのかもっと知りたい人 はhackerethic.orgを参照してくだ さい。


注意:
プログラムの実例を正しく動かしたいのなら、テキストファイルに保存 してからインタプリタで動かしましょう。対話インタプリタに直接打ち込むと 動かないものもあります。(この事について質問してこないこと!各自 ドキュメントを参照する。)


動作環境


Pythonでプログラミングをするには、インタプリタをインストールしなければ なりません。Pythonインタプリタはほとんどのプラットホーム用に用意されて います(Macintosh、Unix、Windowsを含む)。インストールに関する詳しい情報 は、Python web siteで見付けることが できます。あと、テキストエディターも準備しておいて下さい。(emacs、 notepadなど)


プログラミングって何?


コンピューターをプログラミングするというのは、コンピューターに命令のま とまりを与えることです。コンピュータープログラムというのは料理のレシピ とよく似ています。例えば[1]

フェスタ風スパム・サラダ

材料:

マリネ:
ライムジュース カップ1/4、
薄口醤油 カップ1/4、
水 カップ1/4、
サラダ油 おおさじ1、
クミン こさじ3/4、
オレガノ こさじ1/2、
唐辛子ソース こさじ1/4、
ニンニク2片みじんぎり、

サラダ:
低塩スパム缶 1缶(12オンス)
    細長く切る、
タマネギ1個 スライス、
ピーマン1個 細長く切る、
レタス、
プチトマト12個 半分に切る、

手順:

マリネの材料をすべて混ぜて瓶に入れ、すき間なく瓶のふたをして
よく振ります。スパム線切りをビニール袋に入れマリネを注ぎます。
袋の口を閉じ、冷蔵庫で30分間漬けます。
30分後スパムを袋から出し、おおさじ2杯のマリネを残します。
そのマリネを大きなフライパンであたため、スパム、タマネギ
ピーマンをくわえます。スパムが焼けるまで3から4分間調理します。
4枚の皿を並べレタスを盛り付け、スプーンで加熱した具をレタス
と混ぜ、半切りのトマトではさむと、4人前の出来上がり。

もちろん、コンピューターはこのレシピは理解できません…。それに、コン ピューターがレシピを理解できたとしても、サラダを作ることができません。 それなら、レシピをもっとコンピューター向けにするために、どう変更する事 ができるでしょう?私たちは(1)コンピューターに理解できる方法で(2)コンピュー ターにできる事を指示する必要があります。


最初のポイントはつまり、私たちが既に手にしているインタプリタプログラム のためのプログラミング言語を使うという事です。ふたつ目は、私たちはコン ピューターがサラダを作れるなんて期待しちゃいけないって事ですね! でも、 数字を足したり何かを画面に表示させるようなことは期待してもいいでしょう。


Hello...


プログラミングのチュートリアルは、ある事をするプログラムを作る事からは じめるという伝統があります。それはつまり、"Hello, world!"を画面に表示 する事です。Pythonでは、そのプログラムは大変シンプルでこうになります。

print "Hello, world!"

これは上に書いたレシピのように基本的です(最もそれより短いですけど!)。 この文はコンピューターに『"Hello、world!"を表示しなさい。』ということ を伝えます。わけないですね。もっといろいろやりたくなりませんか?

print "Hello, world!"
print "Goodbye, world!"

全然難しくなってないですよね?それに、何も目新しいものもないし…私たち は、ぜひスパムサラダの様に材料から何かを作れるようになりたいです。じゃ あ…私たちはどんな材料を持っているんでしょう?まずひとつ目に、"Hello, world!"のような文字列があり、数字もあります。手始めに、コンピューター に長方形の面積を計算させてみましょうか。レシピは次のような短いものにな ります。

# The Area of a Rectangle

# Ingredients:

width = 20
height = 30

# Instructions:

area = width*height
print area

たぶんあなたは、スパムサラダのレシピと(ちょこっとだけ)似ていると思うで しょう。でもどういう風に動くんでしょう?まず最初に、# ではじまっている 行はコメントと呼ばれ、コンピューターからは全く無視されます。しかし、こ の文の様に細かい説明を入れる事は、あなたのプログラムを人間から読みやす くするためには、とても重要になって来ます。


次は、foo = bar というような文ですが、これはアサインメントと呼ばれ、 このwidth = 20という例では、widthは20としますよという事を指示してい るところです。ところで、"widthは20"とはどういう意味でしょう?これはつま り"width"という変数がつくられて(すでに存在しているなら再利用され)20と いう値がそれに与えられるということです。つまり、その文より後にwidthが 使われたなら、コンピューターは値を知っているということになります。つま り、

width*height

20*30

と同じわけです。計算値は600になり、その値は"area"という変数に割り当て られます。プログラムの最後の文は"area"変数の値を表示します。つまり、あ なたがこのプログラムを起動すると、単に

600

とだけ表示されます。

注意:
Python以外の言語によっては(サラダの材料のように)プログラムの先頭 で、どんな変数が必要かコンピューターに教えなくてはならないものもありま す。Pythonは賢いのでその必要はありません。


フィードバック


さあ、これであなたは単純なものでも複雑なものでも計算できるようになりま した。それは本当か確かめるために、あなたは長方形の代わりに円の面積を計 算してみたくなるでしょう。

radius = 30

print radius*radius*3.14

しかし、これでは長方形の時より全く目新しいというわけでもありません。少 なくとも、私にはそう思えます。それに、このプログラムは、あんまり融通が 利きません。もし私たちの見たい面積が半径31だったら?どのようにしてコン ピューターに知らせますか?これは少しサラダのレシピにあった"スパムが焼け るまで3から4分間調理します"というの似にています。いつ焼けたか知るため には、確かめないといけませんね。そう、私たちはフィードバック(確認行為) かインプット(3から4分という時間)が必要です。どのようにコンピューターは、 円の半径を知ればよいでしょう?このプログラムはインプットを必要としてい ます…以下のようにすると私たちは、半径を尋ねるようにする事ができます。

radius = input("What is the radius?")

print radius*radius*3.14

さあ、プログラムがかっこよくなってきましたね…inputというのは関数と呼 ばれるものです。(inputはPython言語に組み込まれている関数で、もう少しす ればあなたも関数を自分で作れるようになりますよ)。ただ単に、

input

と書いても何もされません…inputの後ろに一対の括弧を付けなければなりま せん。そうすることで、input()は動きます。この関数は単純にユーザーが半 径を入力するのを待ちます。上のバージョンではプログラムは、少しだけユー ザーフレンドリーになりました。質問を最初にするというだけですけど。私た ちが"What is the radius?"のような質問用の文章をその関数を呼出す括弧の中 に入れるとそのパラメーターが渡されて関数が呼ばれます。括弧の中にはいっ ているものがパラメーターです。このプログラムの場合、私たちは質問をパラ メーターに渡すのでinputはユーザーから入力を受ける前に何を表示すればよ いかを知る事ができます。


でもどうやって半径の値を受けとるのでしょう?inputという関数は呼び出さる と、(その他多くの関数と同じく)値を返します。別にこの値は使わなくてはい けないというわけではありませんが、このプログラムには、使いたいですね。 以上の事から、以下の2つの文は全く違う意味になることがわかります。

foo = input

bar = input()

上の例では、fooはinput関数"自身"が格納されました(つまり、foo("What is your age?")のようにつかえるということです)。これを動的関数呼びだしと言 います。barにはユーザーからの入力が格納されます。


流れ


さあ、これで私たちは簡単な動作(計算と表示)とユーザーからの入力を受け付 けるプログラムを書けるようになりました。このプログラムはとても便利です が、決まった動作しか実行することができません。次は、どうにかこれを直し て行きたいですね。ほとんどのスパム・サラダのレシピも上のプログラム似に て、決まった手順が書かれているだけです。でも、もし私たちが、コンピュー ターにスパムの焼け具合を確かめるように指示するにはどうしたら良いでしょ う?もしそれが焼けているならオーブンから取り出さなくてはいけないし、そ うじゃないならもう少し焼かないといけません。これを伝えるにはどうしたら 良いでしょう?


私たちのしたいことは、プログラムの流れを制御することです。プログラムの 流れは「スパムを取り出す」、「そのままにする」 の2つに分かれています。 それを選ぶのは私たちです。大事なのは、スパムがちゃんと焼けたかどうかと いうことです。それを確かめるのが条件文と呼ばれるもので、以下のようにな ります。

temperature = input("What is the temperature of the spam?")

if temperature > 50:
    print "The salad is properly cooked."
else:
    print "Cook the salad some more."

このプログラムの意味は明らかで、もしtemperatureが50(摂氏)より高いのな ら、ユーザーに加熱が済んだというメッセージを表示し、そうでないなら、も う少し調理を続けるよう伝えます。


注意:インデントはPythonにおいてとても重要です。条件文(ループや関数でも です。このふたつは後で出てきます。)のブロックは(いくつかのスペースか、 スペース8個にあたる"タブ"によって)字下げされていなければなりません。字 下げによって、インタプリタは、始まりと終りを見分けます。それに、インデ ントによってプログラムは、人間に読みやすくもなります。


さあ、再び面積の計算に戻りましょう。このプログラムが、何をするのか分か りますか?

# Area calculation program

print "Welcome to the Area calculation program"
print "---------------------------------------"
print

# Print out the menu:
print "Please select a shape:"
print "1  Rectangle"
print "2  Circle"

# Get the user's choice:
shape = input("> ")

# Calculate the area:
if shape == 1:
    height = input("Please enter the height: ")
    width = input("Please enter the width: ")
    area = height*width
    print "The area is", area
else:
    radius = input("Please enter the radius: ")
    area = 3.14*(radius**2)
    print "The area is", area
この例で出てきた新しい表現:
 


  • printが空の行を表示するためにそのまま使われた。
  • =が右の値を左に割り当てるのに対して、==はふたつのものが 同じか確かめる。このふたつは全然違うものです!
  • **はPythonでは乗算の演算子で、radiusの2乗はradius**2と書けます。
  • printはコンマで分けることで、ひとつ以上のものを表示できます。(表 示の際にはスペースひとつで分けられます。)


プログラムは、いたって簡単です。長方形か円のどちらの面積を計算したいか を、数字で尋ねてその数字をif文(条件文)で、どちらのブロックを面積の計算 に使うかを決めるのに使います。この二つのブロックは、前の例で使われたも のとほとんどいっしょです。コメントがコードを更に読みやすくしているとい う点に気が付くでしょう。いにしえより、プログラミングの第1の掟は"汝、コ メントをするべし"だといわれています。とにかく、これは身に付ける価値の ある良き習慣です。


エクササイズ


上のプログラムを正方形の面積も計算できるように拡張するには、ユーザーが 一辺の長さを入力しなくてはなりません。もし2つ以上の選択肢がある場合は、 このように書きます。

if foo == 1:
    # Do something...
elif foo == 2:
    # Do something else...
elif foo == 3:
    # Do something completely different...
else:
    # If all else fails...

このelifというミステリアスな名前は"else if"を意味します:-)つまり、foo が1ならDo somethingを、2ならDo something elseを実行するということです。 あなたは、もっと他のオプション、三角形や多角形などをプログラムに加えて みたいでしょう。どうぞご自由に!


ループ


順番に実行をしたり条件判断をするのはプログラムのブロックを構築する3つ の方法の内の2つでしかありません。では、3つめは何か、それはループです。 前の章で、わたしはスパムが焼けたか確かめる方法を示しました。しかし、明 らかにこれでは不十分です。私たちが確かめた時に、スパムが焼けていなかっ たらどうしたらよいでしょう?どのようにしてチェックを繰り返す回数を知れ ばいいのでしょう?実は、そんなことはわかりません。それに、わかる必要も ありません。私たちはコンピューターに、それが済むまでチェックし続けるよ うに命令するべきです。では、どうやって?その通り、私たちはループを使います。


Pythonには、2つのループがあります。 whileループとforループです。たぶん、 Forループの方が簡単です。例えば、

for food in "spam", "eggs", "tomatoes":
    print "I love", food

この文は、"spam" ・"eggs"・"tomatoes"の全てをあなたが大好きだと表示し ます。ループの中にあるブロックは全ての要素に対して1回ずつ実行されます。 現在の値がfoo変数(この例では)に入れられます。もうひとつ例を、

for number in range(1,100):
    print "Hello, world!"
    print "Just", 100 - number, "more to go..."

print "Hello, world"
print "That was the last one... Phew!"

rangeという関数は、与えられた範囲の数字のリストを返します(最初の数は含 むが、最後の数は含みません…この例では[1..99])。つまりこのプログラムを 優しく言い替えると、

    ループの中身は、1(含む)から100(含まない)の範囲の数それぞれに対して実 行されます。(ループの本体と残りの文が何をするかを見るのは、課題としてお きましょう。)

しかし、このループはほんとに私たちのスパム焼き加減問題を解決してくれる とはいえません。もし、私たちがスパムを100回もチェックしたいのなら、こ のループはとっても素晴らしい解決法だといえるでしょう。しかし私たちは、 それで十分か、それとも多過ぎるのかというのがわかりません。私たちはただ、 スパムが焼けていない間見張っていてほしいのです。(もしくは、こんがり焼 けるまで。これは、好みによりますね。)ということで、私たちはwhileループ を使います。

# Spam-cooking program

# Fetch the function sleep
from time import sleep

print "Please start cooking the spam. (I'll be back in 3 minutes.)"

# Wait for 3 minutes (that is, 3*60 seconds)...
sleep(180)

print "I'm baaack :)"

# How hot is hot enough?
hot_enough = 50

temperature = input("How hot is the spam? ")
while temperature < hot_enough:
    print "Not hot enough... Cook it a bit more..."
    sleep(30)
    temperature = input("OK. How hot is it now? ")

print "It's hot enough - You're done!"
この例で出てきた新しい表現:
 
  • Pythonでは便利な関数がモジュールに入っていてインポート可能です。 この場合私たちはsleepという関数(与えられた数字の秒間だけ停止する) をtimeというPython付属のモジュールからインポートしています。(自分 のモジュールを作るのも可能ですよ…)


練習1


ユーザーから続けて数字の入力を受け付け、合計が100に近付くまでその数字 を足し続けるプログラムを書きなさい。それとは別に、ユーザーから100個の 数字を受け付け合計を表示するプログラムを書きなさい。


より大きな問題 - 抽象化


あなたがある本の内容を大まかに知りたいと思ったなら、コツコツと地道に読 み進んだりはしませんね。目次を見るでしょう?目次というのは、大まかな表 題を書き並べていますからね。では、今あなたは料理の本を著述していると考 えてみて下さい。レシピのほとんどが"スパムとマカロニのクリーム煮"や"ス イス風スパム・パイ"のようなもので、あなたはスパムの作り方を全部のレシ ピで繰り返したいなどと思いません。(オーケー…スパムを自分で作るなんて ことは実際ないですね。…でもそうしないと話が続きませんからね:))あなた はスパムのレシピを各章ごとに置きたいと思っています。その章の名前を代わ りに書いておけば、毎回完全なレシピを書かなくていいですからね。これを、 コンピューターでは抽象化といいます。


では、与えられた正の数のから整数部分を取り出したいとします。例をいうと、 2.7が与えられたとすれば、2が答です。これは、しばしばその数のフローと呼 ばれています。(これは、Pythonの組み込み関数intを使うと簡単にできますが、 どうぞ我慢を…)さて!どうすればこれをできるでしょう?簡単な解決法は、ゼ ロから順に試していくことです。

number = input("What is the number? ")

floor = 0
while floor < number:
    floor = floor+1
floor = floor-1

print "The floor of", number, "is", floor

floorがnumberより大きくなったところでループが終るということがわかりま すね。わたしたちは、1だけ多めに足してしまいましたので、直後に1引いてい ます。では、複雑な数学の式の"フロー"を調べたい時には、どうしたらいいで しょう?私たちは、"フロー"を調べる必要のあるそれぞれの数ごとに、完全な ループを書かなくてはならないでしょう。全然面白そうじゃないですね…たぶ んあなたは、何か代わりになるものがないかと考えるでしょう。そうです、ルー プの中身を全部、"floor"という我々独自の関数に詰め込んでしまいましょう。

def floor(number):
    result = 0
    while result < number:
        result = result+1
    result = result-1
    return result
この例で出てきた新しい表現:
 
  • 関数は、defというキーワードによって定義される。defの後に関数の名 前括弧の順で書き、括弧の中に必要なパラメーターの名前を書く。
  • もしその関数が値を返す(return the value)なら、returnというキーワー ドによって実現される。(returnが実行されると関数は、自動的に終了す る。)


定義が済んだので、私たちは次のようにそれを使えます。

x = 2.7
y = floor(2.7)

これを実行した後では、yは2でなくてはならないはずです。また次のように関 数は、ひとつ以上のパラメーターを使って作ることもできます。

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


練習2


ユークリッドの互除法によって2個の数の最大公約数を求める関数を書きなさ い。解は次の手順で求めます。


  1. 2個の数を用意し、それをaとbとする。aはbより大きいものとする。
  2. 次の操作をbが0になるまで繰り返す。
    1. aにbの値を代入する。
    2. bに(1.をする前の)aをbで割った余りの値を代入する。
  3. 最終的なaの値を返す。


ヒント:
 


  • aとbを関数のパラメーターとして使いましょう。
  • 簡単にaはbより大きいことを確かめましょう。
  • xがyに割られた時の余りは x % y という式で計算できます。
  • x, y = y, y+1 という風にするといっぺんに値を代入できます。こ

の例では、xには(加算される前の)yが代入され、yは1加算されます。


関数についてさらに学ぶ


練習はどうでしたか?難しかったですか?関数について、まだちょっと混乱して いますか?どうか心配しないで下さい。話題はもうそんなに残っていませんか ら。



私たちが、関数を作った時のような抽象化は、しばしば手続き抽象といわれ、 たくさんの言語が手続きという言葉を関数という意味で使っています。実際、 コンセプトは違うけれどPythonでは両方とも関数という呼び方で統一していま す。(多かれ少なかれ、このふたつは同じやり方で定義され、同じやり方で使 われてます。)


では、関数と手続きとは(他の言語では)何が違うのでしょうか?そうですね、 前の章で見た通り、関数は値を返すことができます。比べて、手続きは値のよ うなものは返しません。このように、一方は何かをして、もう一方はしないと いう風に関数をふたつのタイプに分けると便利なことがよくあります。


値を返さない関数(または手続き)のが有用な場合というのは、環境を変えたり する時です(例えば、砂糖とクリームを混ぜて泡立てるとか…)。例を見てみま しょう。

def hello(who):
    print "Hello,", who

hello("world")
# Prints out "Hello, world"

何かを表示するのは副作用と見ることができます。この関数のすることはそれ だけなので、この関数は典型的な手続きといえます。でも、これで環境を変え たなどといえるんでしょうか…では、次の例はどうですか?試してみて下さい。

# The *wrong* way of doing it
age = 0

def setAge(a):
    age = a

setAge(100)
print age
# Prints "0"

何が悪かったのでしょう?問題は、setAge関数が自分用のローカル変数を作っ てしまうというところにあります。setAgeの中でだけ存在するageという同名 の変数が作られてしまったのです。どうやったら、これを避けれるでしょう? それは、グローバル変数というものを使うことで解決します。


注意:
グローバル変数はPythonではあまり使われません。グローバル変数を使 うと簡単にめちゃくちゃな構造のプログラムを作れてしまうからです。そうい うものはスパゲッティー・コードと呼ばれています。ここでは、より複雑なテ クニックに話を持っていくためにグローバル変数を使いますが、どうか御自分 でプログラムを作る際には、避けるようにして下さい。


インタプリタに、その変数はグローバルだと伝えること(global ageという様 な文で)によって 私たちは、変数を内側で新しいものを作る代わりに、関数の 外側で使うことができます(グローバルとローカルという風に対比されます)。 さっきのプログラムを書き直しましょう。

# The correct, but not-so-good way of doing it
age = 0

def setAge(a):
    global age
    age = a

setAge(100)
print age
# Prints "100"

あなたが、オブジェクトについて(後の章で)学ぶ時、ageというオブジェクト とsetAgeというメソッドでこの機能を実現する方がより適切であるということ がわかると思います。データ構造の章では、より良い例をお見せします。では、 関数についてはどうでしょう?一体、関数とは何なのでしょう?数学では関数と いうのは、いくつかの入力から結果を計算する"機械"のことをいいます。それ は入力値が同じなら、いつも同じ結果を返します。例を挙げると、

def square(x):
    return x*x

これは、数学のf(x)=x^2(xの2乗)というのと同じことをします。この関数 は数字がひとつ入力されること期待し、環境を変えるようなことはしません。


関数の種類をふたつにわける:
ひとつ目は、手続きのように結果を返さないも の。ふたつ目は、数学の関数のように(ほとんど)何も変えないけど、結果を返 すものです。もちろん、この極端なふたつの中間のようものを作ることもでき ます。でも何かを変える時は、そのことを十分明確にしておくべきです。名前 の付け方を工夫するのもいいかも知れません。例えば、"純粋"な関数には、 square(四角形)のような名詞を、手続きのような関数には、setAgeのような命 令文を使うというのはどうでしょう?


さらなる材料 - データ構造


入力を受け付け方、表示のやり方。アルゴリズム(プログラム)をひとつの構造 にまとめ、それを使うやり方。などなど、ここまでにあなたは本当にたくさん のことを学びました。では次は、その中でもとびきり素晴らしいものを学びま しょう。


ここまでに私たちは、どんな材料をプログラムの中で使ってきたでしょう?数 字と文字列ですね。合ってますか?でも次に紹介するものには、幾分か退屈… いえいえ、そんなことはありません。今のは、忘れて下さい。さあ、話をもっ と面白くするために次のふたつの材料を紹介しましょう!


データ構造というのは、データを構造化したものです(まあ、びっくり!)。数 字ひとつだけでは、構造があるとは言えませんよね。もし、私たちがたくさん の数字をひとつのいれものの中に突っ込みたいとします。そうすると、それ には構造があるといえます。例えば私たちが、数字のリストを作りたければ、 簡単に

[3,6,78,93]

とすればよいだけです。リストについてはループの話をした時に少し触れまし た。でも、あれでは十分とは言えません。リストは、上の例のようにコンマで 分けられた要素を、大括弧で括るだけでできます。


さあ、例題にいきましょう。以下は、素数(1だけで割れる数)を計算するプロ グラムです。

# Calculate all the primes below 1000
# (Not the best way to do it, but...)

result = []
candidates = range(3,1000)
base = 2
product = base

while candidates:
    while product < 1000:
        if product in candidates:
            candidates.remove(product)
        product = product+base
    result.append(base)
    base = candidates[0]
    product = base
    del candidates[0]

result.append(base)
print result
この例で出てきた新しい表現:
 


  • 組み込み関数rangeは、他のリストと全く同じように使えるリストを返 します。(そのリストは、最初のパラメーターは含むけど、最後のパラメー ターは含みません。)
  • リストは、論理値(yesとnoとかtrueとfalseの事)に使えます。もしリス トが空でないなら、ture。空なら、false。つまり、whileループに使うと "リストの中身が空でない間(while)繰り返す。"という風な意味になりま す。
  • ある要素があるリストの中にあるかを、簡単に確かめる事ができます。
  • someList.remove(someElement)のように書くと、someElementを someListから消すことができます。
  • someList.append(anotherList)のように書くと、あるリストを他のリス トに追加(append)することができます。実際に"+"を使っても(someList = someList + anotherListのように)同じ事ができますが、こちらはあ まり効率が良くありません。(つまり、appendより処理が遅いという事で す。)
  • 大括弧によってリストの中での位置(0から数える)を指し示す事で、そ の位置の値を得る事ができます。つまり、someList[3]とするとsomeList の4番目という事になります。
  • キーワードdelを使って変数を削除する事ができますが、リストの(その 位置の)要素を削除するのにも使う事ができます。つまり、del someList[0]はsomeListの最初の要素を消します。もし、リストが削除の 操作の前に[1,2,3]だったとしたら、操作後は、[2,3]になります。


ミステリアスなリスト要素の操作方法を説明する前に、例題に対して短い解説 をしておきましょう。


このプログラムで使われているのは、"エラストテネスの篩(ふるい)"(訳注:誰 かこれで訳が合っているのか教えて下さい!)と呼ばれるアルゴリズム(か、そ れに似たもの)の説明です。候補になる数字の集まり(この場合は、リスト)を 対象に素数以外の数字をどんどん消していきます。その数が素数かどうやった らわかるかですって?素数以外の数はふたつ以上の数に分けることができる事 を利用するんです。


私たちは、[2...999]の数字のリストを対象に処理を始めます(対象のリストは、 [3...999]ですが、2は最初のbaseなので、2もちゃんと対象に含まれます)。な ぜかというと、私たちは1000より小さい数の素数を知りたいからです。1は素 数だというのは、みんな知っているでしょう(まあ、実際は尋ねる人によって 回答は違うでしょうけど)。私たちはまた、それまでの結果を格納するresult というリストと、baseという変数も持っています。resultは最初、数字の1だ けを格納しています。私たちのプログラムは、繰返しごとに、base(常に対象 リストの中で最小の値になる)の倍数を対象のリストから消すというアルゴリ ズムを実行します。繰り返しのブロックが1回実行された後、私たちは、 candidates[0]の数が素数だとわかっています。(なぜならbaseに使われたより 小さな数は、削除されているからです。どうです、わかりましたか?)。そうい うわけで、私たちはその数字をresultの方に追加して、candidates[0]を新し いbaseに設定して、candidates[0]をcandidatesリストから削除するのです。 candidateリストが空になったら、resultの方は全部の素数を格納していると いうわけです。うまいやり方でしょ?


考えておこう:
繰返しの1回目だけで起こる特別なことは何でしょう?この時 baseは2ですが、これも"篩(ふるい)"にかけられた数でしょうか?では、なぜそ うではないのでしょう?なぜbaseが他の数の時にはそのような問題が起きない のでしょう?なぜ全ての対象をcandidateリストに入れることができないのしょ う?


さあ、次は何でしたっけ。ああ、そうでした…リストの要素を操作する方法で したね。それと、スライスについても学びましょう。Pythonにおけるリストの、 個々の要素を扱う方法はいくつかありまして、あなたはすでにインデックス参 照という、いちばん普通なやり方については見てきました。それはあまりにも 単純なので、あるひとつのことを除いてはインデックス参照について全部教え てしまいました。そのひとつというのは、負の数でリストの後ろからの番号を 指定できるという事です。つまり、someList[-1]というのは、someListの最後 の要素のことで、someList[-2]というのはそのひとつ前、といった具合です。


しかし、スライスというものについては、まだ触れていませんでしたね。スラ イスというのはインデックス参照に似たところがありますが、スライスにはひ とつの要素だけでなく、範囲で指定する事ができるという違いがあります。で はどうするのか、例を見てみましょう。

food = ["spam","spam","eggs","sausages","spam"]

print food[2:4]
# Prints "['eggs', 'sausages']"


オブジェクトとオブジェクト指向プログラミングによる、さらなる抽象化


"オブジェクト指向プログラミング"という巷で噂の言葉を、耳にした事はあり ませんか?


章題からわかるように、オブジェクト指向プログラミングというのは、プログ ラムの詳細を抽象化する数ある手段の内のひとつです。手続きとは、複雑な操 作を与えられた名前に抽象化する事です。OOP(オブジェクト指向プログラミン グ)では、そう扱わずにオブジェクトとして扱うわけです(大いに驚きました か?)。例えば、私たちがスパム調理プログラムを作ったとします。そのプログ ラムでは、温度、時間、材料等々…のさまざまな物事を扱う手続きを作る代わ りに、それらをスパム-オブジェクトという塊にまとめることができます。ひょっ としたら、オーブントースター-オブジェクトや時計-オブジェクトというふう のも作るかもしれませんね…温度のようなものはスパム-オブジェクトに属し ていて、時計-オブジェクトから、時間を読んでいます。そして、プログラム に何かをさせたければ、私たちは、オブジェクトに何らかのメソッド(方法)を 教えなければなりません。例えば、オーブントースターはスパムの調理法を知っ ているかもしれません。といったことです。


では、これをPythonでつくるにはどうしたらよいでしょう?オブジェクトを直 接作ることはできません。私たちはオーブントースターを作る代わりに、オー ブントースターとはどういったものかというのを記述したレシピを作ります。 このレシピは、私たちがオーブントースターと普段呼んでいるもののクラスを 記述しています。とても簡単なオーブンのクラスはたぶん、こうなるでしょう。

class Oven:
    def insertSpam(self, spam):
        self.spam = spam

    def getSpam(self):
        return self.spam

どうです?この例は訳の解らないものがつまった、気味の悪い代物に見えるん でしょうか?


この例で出てきた新しい表現:
 


  • オブジェクトのクラスはキーワードclassによって定義されます。
  • 関数や変数(同じくメソッドも属性も)の名前は小文字で始めますので、 クラスの名前は普通、大文字で始めます。
  • メソッド(つまり、オブジェクトがどう実行するか知っている関数や、 操作)は、クラスのブロックの中で普通に定義できます。
  • 全てのオブジェクトのメソッドは、self(またはそれに近い名前の…)と 呼ばれる第1引数をもっていなければなりません。理由は、(幸いな事に) もうすぐ明らかになります。
  • 属性と、オブジェクトのメソッドは以下のようにアクセスされる。

    mySpam.temperature = 2 や dilbert.be_nice()


まだ、例題についてよくわからない点がある事と思います。例をあげるなら、 selfって何なの?とかですね。今、私たちはレシピ(もちろんクラスで)を持っ ています。ここからどうやってオブジェクトを作ったらよいのでしょう?


私たちは勇敢にも、結論からぶつかっていきましょう。オブジェクトというの は、クラスの名前を関数のように呼び出すことで作る事ができます。

myOven = Oven()

myOvenは今Ovenオブジェクトを格納しています。これを、一般的にOvenクラス のインスタンス(実体)といいます。同じようにSpamというクラスを私たちがす でに作っているなら、以下のようにできます。

mySpam = Spam()
myOven.insertSpam(mySpam)

myOven.spamには今、mySpamが格納されました。なぜなら、私たちがオブジェ クトのメソッドを呼び出した時、最初のパラメーターには常にそのオブジェク ト自身が格納されるからです。(みなさん、ついてきてますかー?)よって self.spam=spamという文はそのオブジェクトのspam属性に変数spamの値を 格納するという意味になります。ともにspamという名前ですが、例題に出てく るふたつのspamは別物だという点に気をつけて下さいね。


練習2の回答


これは、とても簡潔なアルゴリズムのバージョンです。


def euclid(a,b):
    while b:
        a,b = b,a % b
    return a


参考図書


[1] Recipe for Fiesta Spam Salad taken from the Hormel Foods Digital Recipe Book



Copyright (c) Magnus Lie Hetland


印刷用ページ
Copyright © 2001-2009 Python Japan User's Group.

警告当サイトの文書・画像等のコンテンツの著作権は、各コンテンツの作成者、もしくは日本Pythonユーザ会に帰属します。
 また、日本Pythonユーザ会はサイト内のコンテンツに他のプログラミング言語からの乗り換えを誘発する恐れのある表現が多々あることを認め、予めお詫び申し上げます。