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

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

新たな気付き(Chapter 8)

  • 集合は同じ値を含まないので、リストをset()で集合にして、それをlist()でリスト化すると、重複要素の除去ができる。
  • リストやタプルと同様にset(文字列)で文字列を1文字ずつバラバラにして集合にできる。ただし、重複要素は削除される。
  • 集合を操作するメソッド:
    • add()で要素の追加。当然同じものは追加されない。
    • remove()で要素の削除。ないものを削除しようとするとエラーになる。
    • clear()で全ての要素を削除して集合を空にする。
    • pop()で要素を一つ切り出す。ただし、集合には順序がないので最後の要素という概念もないので何が取り出されるかはわからない。
  • frozensetは変更不可の集合を作る。なので上のメソッドは使用できない。
  • 内包表記もリスト同様に利用できる。
  • 和集合の書き方(全ての要素):a|b|c、もしくはa.union(b,c)
  • 積集合の書き方(重なる要素):a&b&c、もしくはa.intersection(b,c)
  • 差集合の書き方(固有の要素):a-b、もしくはa.difference(b)
  • 対称差集合の書き方(重なってない要素):a^b^c、もしくはa.symmetric_difference(b,c)
  • 集合関連のメソッドは以下:
    • update(b,c)で元集合にない要素が追加される。要するに和集合になる。|=演算子も同じだけど集合1個ずつになる。
    • intersection_update(b)で、元集合とbの共通する要素のみの集合になる。つまり積集合になる。&=演算子と同じ。
    • difference_update(b)で元集合とbの共通する要素が除去され元集合固有の要素だけが残る。つまり差集合になる。-=演算子も同じ。
    • symmetric_difference(b)で元集合とbの要素の共通の要素のない元集合とbの固有の要素で構成される。つまり対称差集合になる。^=演算子も同じ。
    • isdisjoint(b)で元集合とbに共通の要素がない場合はTrue、共通の要素があればFalseが返る。
    • issubset(b)で元集合がbに完全に包含される下位集合である場合はTrue。<=演算子も同じ。
    • issuperset(b)で元集合がbの要素を全て含みbを包含する上位集合である場合はTrue。>=演算子も同じ。

新たな気づき(Chapter 7)

  • タプルの要素が1つのときは2つ目以降の要素がないとしても(a,)とカンマをつける。
  • tuple(range(-5,5))で-5から5までの整数のタプルができる。
  • tuple("日月火水木金土")で曜日1文字づつにばらけて7つの要素を含むタプルができる。
  • tuple(list_a)でリストをタプルに変換できる。
  • 逆にlist(tuple_a)でタプルをリストに変換できる。
  • ==は値が同じかどうかを調べ、isはオブジェクトが同じかどうかを調べる。なのでa=(1,2,3)とa=bとc=(1,2,3)を比較する場合、a==b、a==cはTrueだけど、a is bはTrueだけど、aとcは値が同じでも違うオブジェクトなのでa is cはFalseになる。
  • zipで複数オブジェクトをつないでリスト化すると、各リストの要素を順番にタプルにしたもののリストが帰ってくる。
>>> x=[1,2,3]
>>> y=[4,5,6]
>>> z=[7,8,9]
>>> xyz=list(zip(x,y,z))
>>> print(xyz)
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
  • アンパック代入という言葉がある。下の事例のようにタプルdataに要素が入っており、変数a,b,cに対してdataに入っている各要素をばらして(アンパックして)代入することが可能。登園a,b,c,d=dataだったり、a,b=dataだったりするとタプル内の要素数と合わないのでエラーになる。
>>> data=(108,76,98)
>>> a,b,c=data
>>> a
108
>>> b
76
>>> c
98

新たな気づき(Chapter 6-3、6-4)

  • list_a.sort()はリストを書き換えてしまうが、list_b=sorted(list_a)は新たなリストを作る。
  • list_a.sort(reverse=True)、list_b=sorted(list_a,reverse=True)で降順にする。
  • リストの中の並びを単に逆にしたい場合はlist_a.reverse()(これExcelにはない)
  • list_a.sort(key=len)のように関数をキーにして文字の大きさ順にソートすることもできる。
  • list_a.sort(key=str.lower)で文字列のリストの中身を小文字にした上でソートできる。しないと大文字が先に来る。
  • 以下のようにすると、番号付きリストにできる。iとwhoを入れ替えてもかまわない。いずれにせよ最初の変数が数字、次の変数がリストから取り出した名前。(names,1)の1を置くことでカウンターの開始数値を1にできる。
names=["埋木","梅本","呻き","梅なんとか"]
for i, who in enumerate(names,1):
    print(i,who+"さん")
1 埋木さん
2 梅本さん
3 呻きさん
4 梅なんとかさん
  • zip関数を使うことで2つのリストをまとめてまわすことができる。
family=["埋木","梅本","呻き","梅なんとか"]
first=["幽閉","横柄","遊兵","幽霊"]
fullname=[]
for n1, n2 in zip(family,first):
    fullname.append(f"{n1} {n2}")
print(fullname)
  • リスト内包表記を使うことで上のコードは以下の様に書き換えられる。
family=["埋木","梅本","呻き","梅なんとか"]
first=["幽閉","横柄","遊兵","幽霊"]
fullname=[f"{n1} {n2}" for n1, n2 in zip(family, first)]
print(fullname)
  • リスト内包表記には条件式を含むこともできるし、複数の条件式でもいい。全ての条件式を満たすものが残る。
numbers=[2.1,9,"梅岡",8.0,"阪急梅田",1.6]
only_numbers = [num for num in numbers if isinstance(num,(int, float)) if num>5]
print(only_numbers)
  • data=[[1,2,3,4],[5,6,7],[8,9]]に対して以下のようにfor inを並べて書くと、
data=[[1,2,3,4],[5,6,7],[8,9]]
result1=[num*2 for alist in data for num in alist]
print(result1)
# [2, 4, 6, 8, 10, 12, 14, 16, 18]

リストの構造が崩れて単一のリストになってしまう。しかし、以下のように[[内側のネスト]外側のネスト]のように表記するとリスト構造が維持される。

data=[[1,2,3,4],[5,6,7],[8,9]]
result2=[[num*2 for num in alist] for alist in data]
print(result2)
# [[2, 4, 6, 8], [10, 12, 14], [16, 18]]

ちなみに、2つ上の事例でresult1=[num*2 for num in alist for alist in data]はエラーになる。やるにしても外側のネスト→内側のリストの順に書く。

  • 例えばlist_a=["呻き遊兵","梅玉幽閉","阪急梅田駅"]というリストに対して、"梅玉" in list_aとやっても、全く同一のデータがないので、Falseで返ってくるので、リストの文字列の一部があるかどうかを検索したい場合は以下のようにリストの中の文字列要素を一つづつ取り出してあるかどうかを確認することになる。
name=input("調べたい名前を入れて下さい:")
result3=False
for item in fullname:
    if name in item:
        result3=True   #あったらresult3をTrueで書き換える。
        break
print(result3)         #なければ書き換えられない元のFalseが表示され、あったら書き換わったTrueが表示
  • list_a.index("a")でaが何番目に含まれるかを表示。なければエラーが出るので、エラーが出そうな場合は例外処理を組み込んでおく。
  • list_a.count("a")でaが何個含まれるかを表示する。先ほどと同様にaxは違う扱い。
  • randomもしくはsecretモジュールのchoiceを利用すると、random.choice(list_a)とするとランダムに要素がピックアップされる。

新たな気づき(Chapter 6-2)

  • list_a.extend(list_b)はlist_a+list_bと同じ効果を得るが、list_aを不可逆に変更してしまう。list_c=list_a.append(list_b)とやってもNoneになってしまう。
  • list_a.append(list_b)はlist_aの中にリストとしてlist_bを追加。appendもlist_aそのものを不可逆にいじる。以下同様。
  • list_a.append("a")とlist_a += "a"は同じ。
  • list_a[i:j:k]で最後のiからjまでk間隔で抜き出し。
  • list_a[i:j][::k]とすると、[i:j]で抜き出したものを更にk間隔で抜き出す。list_a[::k][i:j]はk間隔で抜き出したものに対してiからjを抜き出す。[i:j:k]とも違う結果になる。
  • list_a[::-k]は逆から取り出す。
  • リストの比較はisまたは==でTrueで帰ってくると同じ。is notは同じでないならTrue
  • list_a=list_bとやったあと、list_bに変更を加えてもlist_aには変更はされない。
  • list_b=list_aをやるとisで比較するとTrueになるが、list_b=list_a.copy()、list_b=list_a[:]、list_b=list(list_a)で比較しても、中身はおなじに見えるが違うオブジェクト扱いでisで比較してもTrueにならない。

新たな気づき(Chapter 6-1)

  • list_a = [0]*10で0の10個入ったリストが作れるが、list_bもリストとすると、list_a = list_b *10もできる。
  • list("happy")やlist("日月火水木金土")のように単語をリスト化すると、結果は1文字ずつバラバラにされたリストができる。
  • list(range(0,10,2))で0-8の偶数が取れて、list(range(1,10,2))で1-9の奇数が取れる。
  • list()で空リスト生成。[]と同じ。
  • list_a[6]で7番目、list_a[-1]で一番最後の要素を取り出す。
  • list_c=[list_a,list_b]で多重リストが出来る。単層リストに要素が加わるlist_d=list_a+list_bとは違う。
  • len(list_c)は2だけど、len(list_d)はaとbの要素数の合計となる。
  • 多重リストの場合は、list_c[1]で2番目の大リスト全てを取り出し、list_c[1][0]で2番目の大リストの中の1番目の要素を取り出す。
  • リストの操作でよくあるエラーが範囲外を指定するIndexErrorなので、try〜except IndexError:構文で例外処理をすると良い。
  • list_a.append('a')でlist_aの一番後ろに追加される。
  • list_a.insert(3,'a')でlist_aの3番目の次に挿入される。
  • list_b = list_a.pop()でlist_aの最後の要素が抜き取られて削除され、list_bができる。pop(n)でn+1番目が抜き取られる。
  • list_a.remove("a")でaが削除される。これの使いみちは、リストに複数の削除したい要素が入っているときに次のように処理できる。
colors =["赤","黒","黒","黒","青","黄"]
print("削除前:",colors)
while "黒" in colors:
    colors.remove("黒")
print("削除後:",colors)
  • 文字列.split(セパレータ)で文字列あるいは文章をリストにする。例えば文章.split()とすれば文章に含まれる単語でリストが作成される(()とセパレータを指定しない場合スペースがデフォのセパレータになる)。csvファイルの行に.split(",")適用すると、pythonのリストができる。
  • del list_a[2]でlist_aの3番めを削除。del list_aでlist_aを丸ごと削除
  • "a,b,c,d,e,f,g,h,i".split(",",3)で['a','b','c','d,e,f,g,h,i']という感じのリストができる。
  • result_list="a,b,c,d,e,f,g,h,i".split(",",3)[:3]で['a','b','c']ができる。
  • セパレータ.join(リスト)で.splitの逆の操作ができる。リストから文章や文字列を再構成できる。

Python3入門ノートの感想

僕は書評とかとにかく苦手なんですけど、これはいいと思います。これなら一通り読み終えると次に進めそうな気がしてきました。みんPyに比べると、体系だってる、という感じです(スタートブックは論外)。ということで、スタートブックとみんPyをマンション1階のゴミ捨て場に放り込んできました。

新たな気付き集(Chapter 5)

条件分岐、繰り返し、例外処理のチャプターです。読み進めるほど、この本いいわあと思います。章の並びの唐突さとかがないし、関数は引数をどう入れるべきか定義っぽく示してくれるし。最初の2冊なんかいらんかったんや!時間のムダやったんや!って感じです。さて、以下備忘録です。

  • ifにifをネストするよりもif(条件式A)and(条件式B)and(条件式C)としたほうがシンプルでよい。
  • 不等式を繋げる場合は、if(a=>-5)and(a<=8)もいいけど、if -5<= a <= 8: みたいな書式も可能。Excelではできないけど。
  • Falseと同じとみなされる戻り値にNone, 0, 0.0, "", (), [], {}等がある。戻り値がTrueかFalseかで条件分岐をさせるコードは以下のように書ける。つまり戻り値がTrueだとifに続く式が実行される。
name=input("名前を入れて:")
if not name:              #上を未入力で返すとnot nameがTrueになるので次の式が実行
    name="匿名"
print(name)
from random import randint
num=randint(0,100)
if num%2:         #奇数で余りが1だとTrueになるので、次が実行される。
    result="奇数"
else:             #偶数で余りが0だとFalseになるので、上が実行されず次が実行される。
    result="偶数"
print(num,result)
  • while 条件式でループを作るが、while Trueで無限ループを作れる。普通はbreakを入れてループから抜け出せるようにする。
from random import randint
while True:
    a = randint(1,13)
    b = randint(1,13)
    if a+b==21:
        break        #合計21になったらループを出る
print(a,b)
  • while 条件式の中にcontinueを入れると、continue以下がすっ飛ばされてループが繰り返される。
from random import randint
numbers=[] #空のリストを作成
#10個の違う正の数字の入ったリストを作成
while len(numbers)<=10:
    n=randint(-10,100)
    if n<0:
        print("マイナスの数字が出たので中断されました。")
        break         #マイナスの数字が出たら中断。elseブロックすら実行されない
    if n in numbers:
        continue      #同じ数字がリストにあったら次を実行せずやり直し
    numbers.append(n)
else:
    print(numbers)
  • while〜else文の場合、whileの中にbreakがあってそれが実行された場合はelseの中は実行されない。elseはwhileをFalseで抜けた場合のみ実行される。
from random import randint
numbers=[] #空のリストを作成
#10個の違う正の数字の入ったリストを作成
while len(numbers)<=10:
    n=randint(-10,100)
    if n<0:
        print("マイナスの数字が出たので中断されました。")
        break         #マイナスの数字が出たら中断。elseブロックすら実行されない
    if n in numbers:
        continue      #同じ数字がリストにあったら次を実行せずやり直し
    numbers.append(n)
else:
    print(numbers)
  • for文もbreakで中断するとelse以降は実行されない。
  • エラー発生等例外が発生する可能性のある処理を行う場合は、tryで試し、エラーがだめならexceptをやる。エラーが出ない場合にelseの塊が実行され、finallyはエラーが出ようが出まいが実行される。
sum=300000000
while True:
    num=input(f"銀行強盗で{sum:,}円をゲットしましたが何人で山分けしますか?数字だけを入力してください。(qで終了):")
    if num=='q'or num=='q':
        print("終了しました。")
        break
    try:     #数字を入力された場合に実行
        price=sum/int(num)
    except ValueError:
        print("qか数字だけを入れろつったよな?幼稚園児かてめえ")
    except ZeroDivisionError:
        print("ゼロで割り切れると思うのか?中学校からやり直せクソ野郎")
    except Exception as error:  #上で数字以外を入れられてエラーが出た場合実行
        print(error,"ってわけわかんねえエラー出たぞボケが")
    else:
        if price<0:
            print("マイナスでどう分けようっての?馬鹿なの?死ぬの?")
            continue
        else:
            print(f"一人あたりの山分け額は{price:,.0f}円です。")
    finally: #エラーが出ようが数字以外が入力されようが実行
        print("次行ってみよう。")