事業企画1年目のpython学習6.0日目

# 本記事について
とある事業会社で事業企画をやっています。
元々は、新規営業1年→エンプラ営業3年やっていました。
事業企画への異動に伴って、ルーチンワークの自動化やスクレイピングに興味を持ちpython学習をスタートしました。
目的達成までは記事を執筆予定です。どうぞよろしくお願いいたします。

# 開発環境
jupyterlab

# 使っている本
すっきりわかるpython入門
https://sukkiri.jp/books/sukkiri_python

# 勉強計画
週5日間ミニマム1h勉強する。
最初の1weekは1冊終わらせることをgoalに。
start@ 2022/2/21

# 学習時間
2.0h

# 学び
今日はオブジェクトを学んでいきたいと思います。
本の学習としては、ほぼここでおしまいです。

## 値の正体


### format関数って

```py
tpl = '3人目は{}さん'
names = ['kamon','asakura']
names.append('hara')　#ディクショナリnamesに'hara'を追加
message = tpl.format(names[2]) 　#値.関数名()で呼び出す
print(message)
#3人目はharaさん

```

値の従来のイメージあは、tplの中に文字列'3人目は{}さん'を入れていたイメージだが、実は'3人目は{}さん'とformat関数・strip関数・・・が入っていたのだ。
pythonでは、文字列データはformat()やstrip()といった関数がセットに入っていて、1つの値として使うということになっていた。
ということは、今まで変数として追加していた整数や真偽値、リストなどrそれぞれがいくつかの決められた関数を従えています。

```py
num = 10
print(num.bit_length()) #10というデータとbit_length関数がセットになっている。
names = ['kamon','asakura']　#'kamon'と"asakura"というデータとappend関数がセットになっている。
names.append('hara')
#4

```

あるデータとそのデータに関する処理を行う関数が一塊なのをオブジェクトといいます！
pythonにおけるあらゆる値はオブジェクトであります。
オブジェクトに所属する関数は、メソッドといいます。

オブジェクト.メソッド名(引数・・・)で呼び出せます。

おさらいですが、type関数でオブジェクトの型を思い出せます。

どのオブジェクトがどの関数を従えているかは、オブジェクトの型によって従えられており、
公式ドキュメントで確認可能。(https://docs.python.org/ja/3/)

|メソッド名|機能|
|----|----|
|capitalize()|先頭文字だけ大文字、他は小文字に。|
|lower()|すべてを小文字にする|
|upper()|すべてを大文字にする|
|title()|単語の先頭だけ大文字に、残りを小文字にする|
|strip()|文字列の前後の空白を取り除く|
|split(●)|文字列●で区切り、各要素をリストで返す|
|replace(●,■)|文字列中の●部分を■に置き換えた結果を返す|
|count(●)|文字列●が登場する回数を返す|

↑
こういうの覚えるの楽しい。

```py
userinfo = input('お名前を血液型とコンマで区切って一行で入力 >>')
[name,blood] = userinfo.split(',')　　 #リストuserinfoを分割する。
blood = blood.upper().strip() #bloodを大文字に、そして分割してリストで返す
print('{}さんは{}型なので、大吉です'.format(name,blood)) 
#お名前を血液型と感まで区切って一行で入力 >> B,kamon
#BさんはKAMON型なので、大吉です

```

##　オブジェクトの設計図

### classについて
str型の設計図(str class)
各strオブジェクトはみんな同じ関数を持っている。

復習します。

|リテラルによるオブジェクト生成|内容|
|----|----|
|小数点を含まない数字|intクラス|
|小数点を含む数字|floatクラス|
|'や"で囲まれた文字|strクラス|
|[]で囲まれた文字|listクラス|
|{}で囲まれた文字|{~:~}形式ならdictクラス、{~}形式ならsrtクラス|

変数名= クラス名()

```py
int_value1 = 0 #intオブジェクトを作成
int_value2 = int()　#空のintオブジェクト
int_value3 = int(9)　#intオブジェクト中身のデータは9を作成
list_value1 = []　#空のリストを作成
list_value2 = list()　#空のリストオブジェクトを作成
list_value3 = list(('kamon','asakura'))　#2つの要素を持つリストオブジェクトを作成

```

###オリジナルの設計図(class)を作る

```py
#class Hero: #classを定義、名前とhpを定義、関数sleepを作成。sleepはselfとhoursを戻してもらう関数を作成。
    name = 'kamon'
    hp = 100
    def sleep(self,hours):
        print('{}は{}寝た'.format(self.name,hours)) 
        self.hp += hours
​
print('すっきりファンタジーXII')
h = Hero() #変数hは、Hero()クラスであると定義。＝HP１００の勇者kamonがオブジェクトとして誕生
h.sleep(3)　#Hero()内のsleepは3時間であること。
print('{}のHPは現在{}です'.format(h.name,h.hp))

#すっきりファンタジーXII
#kamonは3寝た
#kamonのHPは現在103です

```

このようにオブジェクトに様々な属性やメソッドを持たせて活用していく考え方は、オブジェクト指向プログライミングといいう。楽に楽しく、複雑なプログラムを作っていくのに便利らしい。詳細は今後。

## オブジェクトの落とし穴

### オブジェクトのidentity
元々準備されているクラスやオブジェクトを効果的に使っていくことがpythonを効果的に使いこなせるか否かが決まるところ。
1つ大きな落とし穴として、identityという概念がある。

```py
scores = [80,40,50]
scores2 = [80,40,50]
print('scoresのidentity: {}'.format(id(scores)))
print('scores2のidentity: {}'.format(id(scores2)))
​
if scores == scores2:　#scoresとscores2が等しいかどうか
    print('scores = scores2')
else:
    print('scoresはscores2と違う')
​
if id(scores) == id(scores2):　#scoresのidとscores2のidが等しいか。
    print('scores = scores2')
else:
    print('scoresはscores2とは違う')

#scoresのidentity: 140278886152064 #この値は、毎回変わる
#scores2のidentity: 140278885258560　#この値は、毎回変わる
#scores = scores2　
#scoresはscores2とは違う　#値は変わるため、イコールにならない。

```

変数scoresの中にはオブジェクト自体は入っていません。
この変数の内容の詳細は、identity値のオブジェクトを見てくださいというように、オブジェクトを指し示す数値が入っています。
別のところの実態を指し示すための数値を、参照(reference)といいます。
もう少し詳細見てみましょう。

```py
scores1 = [80,40,50]
scores2 = [80,40,50]
print('scores1の先頭要素は、{}'.format(scores1[0]))
print('scores2の先頭要素は、{}'.format(scores2[0]))
​
print('変数scores2の中身を変数scores1に代入します')
scores1 = scores2
​
print('scores1の先頭要素を90に置き換えます')
scores1[0] = 90
​
print('90を代入したscores1の先頭要素は、{}'.format(scores1[0]))
print('90を代入していないscores2の先頭要素は{}'.format(scores2[0]))

#scores1の先頭要素は、80
#scores2の先頭要素は、80
#変数scores2の中身を変数scores1に代入します
#scores1の先頭要素を90に置き換えます
#90を代入したscores1の先頭要素は、90
#90を代入していないscores2の先頭要素は90 #scores[0]は定義していないのに90になっている

```

7行目では、scores2の中身をscores1に代入していますが、ここでコピーされているものはidentityというただの数値である。つまり、リストをコピーしているわけではなく、参照(reference)しているに過ぎないわけです。

ある変数を代入分でコピーすると、オブジェクトではなく参照がコピーされる。
同じオブジェクトを複数の異なる名前でアクセスできようになる。

つまり、箱より名札に近いpythonの変数。
pythonでは、identity値にわかりやすい名前をつけたものと考えることができます。


### 参照による副作用
先日学んだように、変数の独立性という考え方があり各関数で定義された変数は、基本的に独立していて外部からはアクセスできず同じ名前の変数が関数の外に存在したとしても、全くの別物として解釈できます。
そのため、関数同士でデータををやり取りする場合には、引数や戻り値を使う必要がありました。
そのため、ある関数を呼び出したら自分が使っていた変数と同名の変数を偶然使っていて、変数の中身を壊すなどの心配はありませんでした。

実際にコードを見てみます。

```py
def add_suffix(names): #渡されたリストの名前にさんをつける関数
    for i in range(len(names)):
        names[i] = names[i] + 'さん'
    return names
​
before_names = ['kamon','asakura','kojima']
after_names = add_suffix(before_names)
print('さん付け後:' + after_names[0])　#add_suffixから返されたリスト内の先頭要素
print('さんつけ前:' + before_names[0])　#add_suffixに渡したリスト内の先頭要素
#さん付け後:kamonさん
#さんつけ前:kamonさん

```

これは、引数としてadd_suffix関数にリストbefore_namesを渡しています。
ここで呼び出し先に渡されるのは、リストオブジェクトではなく、before_namesを示す参照(identify値です)
これによりadd_suffix関数のnamesは、before_namesと同じものを指し示すことになります。
つまり、add_suffix関数内でリストnamesの中身を変更してしまうと、呼び出し元のbefore_namesの中身も変更されてしまうのです。


これは、どのプログラミンう言語でも起こりうることなので、気をつけましょう。
防御策としての防御的コピーというのもあります。これはここでは割愛しますが、覚えていきましょう。


###　不変オブジェクト
独立性が崩れないケースもあるので、学びましょう。
・オブジェクトが不変なのは、int型・str型・bool型などの一部の標準な型
・tuple型(コレクションのタプル)

不変オブジェクトを書き換えると、別のオブジェクトとして生まれ変わる。
元のオブジェクトは、捨てられる。

```py
def add_suffix(name):
    name = name + 'さん'
    return name
​
before_name = 'kamon'
after_name = add_suffix(before_name)
print('before name is' + before_name)
print('aftername is ' + after_name)

#before name iskamon
#aftername is kamonさん

```

# 感想　
土曜日は休憩をいただきました。
やろうとは思っていたのですが、リビングでゴロゴロしていたら気づいたら寝ていました。
たまにはそういう日があってもいいとは思います。今日は昨日の分も学習していきました。
色々使いこなせていける未来を思うとワクワクします。
今日は、6.5日目としてモジュールも学んでいきます。
では、良いおやすみをお過ごしください。