40のおっさんのPython学習記録

20年以上前、学部の必修のC言語が全く理解できずに同級生に放り投げ、その後コーディングから遠ざかったガチ文系のおっさんが、ふと思い立ってPythonに挑戦しています。

条件分岐と例外処理

Pythonは条件分岐は

if 条件式1:
    条件式1が満たされる場合の実行式
elif 条件式2:
    条件式2が満たされる場合の実行式
elif 条件式3:
    条件式3が満たされる場合の実行式
else
    上記の条件式のどれも満たさない場合の実行式

という感じ。ExcelのようにIF(IF(...とifの入れ子構造を作らなくてもいいので単純にできそう。

例外処理というのは簡単に言うとエラーを吐いた場合に、エラーはエラーとしてプログラムを続けたい場合の処理方法。

#!/usr/bin/env python
import sys

for fn in sys.argv[1]:
    try:
        f = open(fn)
    except FileNotFoundError:
        print("そんなファイルねえよボケ")
    else:
        try:
            print("ファイルサイズは",len(f.read()))
        finally:
            f.close()

tryの後にエラーを吐く可能性が高い実行式を入れ、exceptの後に例外クラス名を書き込む。例外クラス名とは要するに公式なエラーコードのようなもの。elseの後にエラーが発生しななかった場合の実行式を書く。最後のfinallyの後はエラーが発生しようがしまいが実行する式を書く。

例外処理に使えるものとしては他にはWith分が存在する。

with open(fn) as f:
    print("ファイルサイズは",len(f.read()))

with文の場合はエラーが出た場合はwith文の中には入らず、エラーがでなかったばあいはwith文の中の式が実行される。for exceptよりも場合によっては簡潔に書ける。

躓いておっさんは考えた

過去数エントリーをご覧になられた方は、おっさんの躓きっぷりを十分にご理解いただいていると思う。
ただ、おっさんは思う。おっさんがPythonを学ぶ理由はウェブサイトを作ることでも、ゲームを作ることでもない。おそらくおっさんはPythonを使って統計、データ分析や、そのためのデータファイルの処理、そしてそれらの自動化であろうと思う。思うというのは、理解しているかどうかはともかくとして9章までみんPyを読み終えた時点では、それに使えるっぽいセクションが少ないというよりも、おっさん程度の想定されるユースケースにたいして、今おっさんが躓いているあたりを完全に理解している必要はないのではないかと感じている。みんPyはPythonを通じてプログラミングというものを学びたいという人用と感じる。書名の通り「みんなのPython」なのだが、おそらくおっさんはその「みんな」には入っていないのではないかと感じる。おっさんのようにとりま、データファイルを取り回して分析して、みたいな人間にはこの本は向いていないんではないか、そして、高階関数だの、オブジェクト指向がどういうものがどうだの、おっさんに果たして必要なのか? 多分必要ないんじゃないかと思う。
Pythonスターターブックはあまりにも脈絡がなさすぎて、体系だった知識が得られそうもないと思ったので放り投げ、みんPyにやってきたが、記法等についてはみんPyはより体系だった記述があり、Pythonの作法は身についたように思う。ただ、みんPyの書いてあることを100%理解すべきかと言われるとそうでもないと考えるに至った。わからないところを無理してわかろうと時間をかけるより、さっさと新たな知識を身につけに行く方がいいのではないかと考えるに至った。
みんPyのこの後の章を見るに「10章 例外処理」、「11章 標準ライブラリを使う」、「12章 Pythonとデータサイエンス」、「13章 Python 2」ということで、10章から12章は一応読み込むべき価値はあると思うので先に進もうと思う。ただ、これまでの「6章 クラスとオブジェクト指向開発」、「7章 クラスの承継と高度なオブジェクト指向機能」、「9章 スコープとオブジェクト」については過去2週間正直躓いて停滞しているわけだが、ここに深入りはせず、次にどんどん進んでいこう。
みんPyに続いて、統計、データ処理に有用な参考書を探すことにしたい。

用語がわけがわからん(オブジェクト、インスタンス、アトリビュート)

まず「オブジェクト指向」、おのれや。そうや、今日もおっさん、エセ関西弁ということは、わけがわからんなってイライラしとる、そういうわけや。オブジェクトって言葉がえらい曖昧な何を指してるのやらわからん上に「指向」なんてこれまた曖昧な言葉がついとる。指向ってことはほな何か、別にオブジェクトせんでもええわけか。どう言うわけやコラ、おっさんに言うてみいや。
おっさんはその昔N88 BASICでベーマガを写経し、HyperTalkでスタックを書き、AppleScriptMacの操作を自動化し、Cで爆死した。おっさんのそういう言語経験からすると、オブジェクト指向と言われてもさっぱりわからん。Wikipediaを見てもおっさん憤死しそうになるくらい意味がわからん。そこで、Weblioを見たら比較的わかりやすくこう書いてある。

オブジェクト指向プログラミングにおいて,内部構造をもつデータ。いくつかの内部データと,その内部データを操作する方法をひとまとまりにして管理したものをいう。データの利用方法が統一化されるので,再利用可能なプログラムが記述可能になり,大規模なプログラム開発が容易になる。 → オブジェクト指向プログラミング

これならまだわかる。なんか要するに、なんかデータとか、プログラミングの構成要素を部分部分として扱おうって話なんやな。なんやおっさんわかってきたで(いや、わかってない)。
そして「オブジェクト」とはナンジャラホイということになるんやが、わしが今リファレンスにしとるみんPyでは、オブジェクトはデータとメソッドを合わせたものということになっとる。つまりは、オブジェクトとは、データに加えて、そのデータに対して施すことが可能な処理も含めたもの、ということか。その処理をメソッドと言うと。

次はお前らや。

クラスとはオブジェクトの設計図にあたり、オブジェクトがどのように振る舞うのかという性質を記述したもの、ということ。

インスタンスとはクラスという設計図に基づいて作られたもの。オブジェクトと同じくデータと可能な処理、メソッドを含んでいる。
クラスからインスタンスを作るという流れ、関係をまとめたのが以下のコード。

from from decimal import Decimal # 10進数を取り扱うDecimalクラスを呼び出す
number=Decimal(10)          # Decimalクラスから10進数の数値のインスタンスを作成
print(number)
print(number+20)            # Decimalクラスのインスタンスは数値と同様に定義されているので数値演算可能
print(number.sqrt())        # Decimalクラスに含まれるメソッドで平方根を取得

アトリビュートとは変数のようなもの。”インスタンス名.アトリビュート名”のようにインスタンスに続いてドットで区切って記す。”クラス名.アトリビュート名”で、アトリビュートを後でクラスに追加したり、変数を変更したりすることができる。

class Prism:
    def __init__(self,width,height,depth):         #初期化メソッドを定義
        self.width  = width                          #幅アトリビュートを追加
        self.height = height                         #高さアトリビュートを追加
        self.depth  = depth                          #奥行アトリビュートを追加
    def result(self):                              #体積の計算
        return self.width * self.height * self.depth
#上記クラスではアトリビュートは記述されたが各アトリビュートの初期値は記述されていない

p1 = Prism(10,15,20)                             #p1インスタンスを作成
print(p1.result())                               #Prismクラスを利用してp1の体積を計算
print(p1.height)                                 #p1の高さアトリビュートを表示
p1.height=50                                     #p1の高さアトリビュートを変更
print(p1.result())                               #高さアトリビュート変更後の体積を計算
p1.bottom = p1.width * p1.depth                  #底面積アトリビュートを追加
print(p1.bottom)                                 #底面積アトリビュートを計算

以下の新アトリビュートbarに定義したメソッドfooを代入して新しいメソッドを作ることもできる。

class Atomklass:
    def foo(self): #メソッドfooを定義
        print("this is foo method!")

i1=Atomklass()  #i1インスタンスを作成
i2=Atomklass()  #i2インスタンスを作成
print(i1.foo()) #"this is foo method!"が表示される
i1.bar=i1.foo   #メソッドを新しいアトリビュートに代入
print(i1.bar)   #"this is foo method!"が表示される
print(i2.bar)   #こっちはエラー

アカン

1週間ぶりです。

平日は特に何もやっていません。今日は本当はもくもく会というものに1日参加する予定でした。

おっさんは病的に集中力がないので、自宅でもくもくと勉強をするというのが苦手なので、今までの人生でも何か勉強をする、作業をする場合は外の喫茶店等で営業妨害をしながら、半日から1日居座るというのをやっています。脱線しますが、昔高田馬場にあったBen’s CafeでGMATの勉強を土日は一日中してたりなんかしてたんですよ。MBAの頃はNYUの目の前にあったThink Coffeeがお気に入りの作業場所だったりしたり、とにかくそういう感じです。

で、どうもプログラミングの世界には「もくもく会」というものが一般的にある模様で、それぞれ目的もレベルも違う参加者がもくもくと自分の勉強や作業をするために集っている模様です。実際、おっさんも昨年末、平日の夜のそういう会に参加しまして、本当に参加者同士、会釈程度をするだけで会話もせず、ただ黙々と自分たちの持ち込んだパソコンで作業をしました。こりゃあ、いいなということで今後もこういう会に積極的に参加しよう、そう思って今日のもくもく会に登録しました。

しかし、起きれませんでした。
だってオフトゥンが僕と離れたくないっていうんですから!

仕方なく今日はアキバでホットケーキを食って過ごしました。まる。

わけのわからぬことばかり

備忘録的に、意味不明だったみんPyのセクションをメモっておく。多分事例が意味がなさすぎてわからへんねん。

高階関数(p.249)
def logger(func):
	def inner(*args):
		print("引数:",args)
		return func(*args)
	return inner

def square(a,b):
	return a**b 

newfunc = logger(square)
print(newfunc(2,3))
print(square(2,3))

argsとか*argsとかなんやねん。

ゲッター、セッター、プロパティ(p.283)
class Prop:
	def __init__(self): 			
		self.__x = 0		#アトリビュートの作成
	def getx(self):			#ゲッター
		return self.__x 	#アトリビュートを返す
	def setx(self,x): 		#セッター
		self.__x = x		#アトリビュートに値を入れる
	x = property(getx, setx)	#プロパティを設定

i = Prop() 				#インスタンスの作成
print(i.x)				#アトリビュートxを参照
i.x=10					#xに代入
print(i.x)
print(i._Prop__x)			#xに無理やりアクセス

一体何をしたいんかわからへん。直感的に、データ処理をやりたいおっさんには関係ないんちゃうんか、と思うことにしてすっ飛ばして次に行く。

はい、おっさんはイラついてくるとエセ関西弁が出てきます。

Iteration & Generator

Iteration、エクセラーには反復計算でおなじみの単語だと思う。なので、反復処理をさせる仕組みをここで学ぶわけだ。
例えば、平方数を1から順に出して行こうとするとき、パッと思い浮かぶのは、リスト内包形式を使ったこういうコードになると思うんですよ。

#リスト内包形式
listincl = [x**2 for x in range(1,10)]
print(listincl)

結果は以下のように表示される。

[1, 4, 9, 16, 25, 36, 49, 64, 81]

で、iterationとgeneratorを使うとこう表記できるらしいの。

#ジェネレーター
i = (x**2 for x in range(1,10))

print(next(i)) #print(i)ではダメ

for k in range(9): #iではなくi以外の変数を宣言する必要あってここではk
	print(next(i))

結果は以下のような感じ。

1
4
9
16
25
36
49
64
81

i=の時点で1から81までの数字はすでにメモリ上には生成されている。だからgeneratorと呼ばれる模様。generatorとリスト内包形式の違いは、カッコ。カッコが違う。とにかくカッコが違う。()カッコを使った時点でgeneratorなので、print(i)とかやってもエラーを食らう。generatorで生成したデータを出すにはnext()関数を使わなきゃいけない。結果の1行目はprint(next(i))の結果で、2行目の4以降はfor文以下の結果。
ざっくりいうと、リスト内包形式はドバッと計算結果が全て吐き出されるのに対し、iteration & generatorを使うと、結果を吐き出すタイミングをコントロールできる、という感じかな。でも、iとxとkと3つの変数を使うのはクソうざいな。

参考にしたのはみんPyではなく以下のウェブ記事。
【Python入門】イテレータの使い方を解説 | 侍エンジニア塾ブログ | プログラミング入門者向け学習情報サイト

少数の扱いへの怒りと内包表記の実験

こういう事例があったとしましょう。なんPyの238ページあたりを参考にしています。

str_speeds = "38 アホンダラが 42 ボケカス 20 南港に沈めんぞ 40 誰がクマや 39"
arranged = str_speeds.split()
print(arranged)
speeds     = [int(item) for item in arranged if item.isdigit()]
print(speeds)
print("平均は",sum(speeds)/len(speeds))

半角スペースで区切られた文字列と数字のごちゃ混ぜから数字だけを取り出して平均を取ろうという例です。結果はこう出ます。

['38', 'アホンダラが', '42', 'ボケカス', '20', '南港に沈めんぞ', '40', '誰がクマや', '39']
[38, 42, 20, 40, 39]
平均は 35.8

で、これを各数値を小数点を込みのものにすると、isdigitが効かんのですよ。もちろんint()はfloat()に変えたとしても。で、調べていくと、正規表現を使ったクソめんどくさい処理をしないと、pythonでは文字列と小数点込みの数値の混じったリストから数値を取り出すことは不可能な模様。勘弁してくれや…意味がわからん…おっさんの仕事で扱うデータは株価、P/Eとか小数点込みのデータばっかりやぞ…そういう怒りが事例の文字列のチョイスに反映されています。