変数に変数を代入したら?
by
mizzsugar
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
変数に変数を代入したら? 〜仕組みを知ってハマらないようになろう〜 2020-07-04 Python Charity Talks in Japan @mizzsugar0425 1
Slide 2
Slide 2 text
前提 ● この発表の対象者は初学者です。 ● Pythonで変数に変数を代入した時の仕組みを知り、 安全なプログラムを書けるようになることが目的です。 2
Slide 3
Slide 3 text
お前、誰よ? ● みずきと申します。 ● Twitter: @mizzsugar0425 ● PythonでWebサービスの開発をしています。(Pyramid, Django, PostgreSQL, Nuxt.js, Angular …) ● コーヒーと自転車とPythonが好きです。 3
Slide 4
Slide 4 text
クイズ① 〜枠の中に入るものは?〜 >>> name_1 = 'aaa' >>> name_2 = name >>> name_1.replace('a', 'b') 'bbb' >>> name_1 'aaa' >>> name_2 'aaa' 4
Slide 5
Slide 5 text
クイズ① の答え >>> name_1 = 'aaa' >>> name_2 = name >>> name_1.replace('a', 'b') 'bbb' >>> name_1 'aaa' >>> name_2 'aaa' 5
Slide 6
Slide 6 text
クイズ② 〜枠の中に入るものは?〜 >>> list_1 = [1, 2, 3] >>> list_2 = list_1 >>> list_1.append(4) >>> list_1 [1, 2, 3, 4] >>> list_2 [1, 2, 3, 4] 6
Slide 7
Slide 7 text
クイズ② の答え >>> list_1 = [1, 2, 3] >>> list_2 = l >>> list_1.append(4) >>> list_1 [1, 2, 3, 4] >>> list_2 [1, 2, 3, 4] 7
Slide 8
Slide 8 text
何故List型の時は変わってしまったのでしょうか? 8
Slide 9
Slide 9 text
値が変わってしまった理由は オブジェクトの仕組みにあります。 9
Slide 10
Slide 10 text
Pythonでは全てオブジェクト Pythonでは、int型 str型 List型 … 全てをオブジェクトとして扱います。 10 https://docs.python.org/ja/3/reference/datamodel.html#objects-values-and-types
Slide 11
Slide 11 text
number = 1 # int型のオブジェクト name = 'Taro' # str型のオブジェクト names = ['Taro', 'Jiro', 'Saburo'] # List型のオブジェクト class Person: def __init__(self, name: str, age: int) -> None: self.name = name self.age = age person = Person(name='Taro', age=10) # Person型のオブジェクト 11
Slide 12
Slide 12 text
オブジェクトの識別値を返すid() ● 組み込み関数id()はオブジェクトの識別値(identify)を返します。 ● id()の値が同じならば同じオブジェクトです。 12
Slide 13
Slide 13 text
>>> num_1 = 143748927394325 >>> id(num_1) 139627296785840 >>> num_2 = 143748927394325 >>> id(num_2) # numと同じ値だけれども違うオブジェクト 139627296786576 >>> num_1 += 1 # 別のオブジェクトとして値が代入される >>> id(num_1) 139627305196544 13 Pythonでは1や2などよく使われる数値は最適化のために同じ idになります。
Slide 14
Slide 14 text
副作用とは ● 副作用とは、オブジェクトの値を変更することです。 ● 副作用を伴う操作を許容するオブジェクトを「ミュータブル」なオブジェクトといいま す。 ● 「イミュータブル」なオブジェクトは副作用を許容しません。 14 例: >>> list_1 = [1, 2] >>> list_1.append(3) >>> list_1 [1, 2, 3]
Slide 15
Slide 15 text
ミュータブル・イミュータブルなオブジェクト ● ミュータブルなオブジェクトの例 List型、Dict型、Set型… のオブジェクト ● イミュータブルなオブジェクトの例 int型、str型、Tuple型… のオブジェクト 15
Slide 16
Slide 16 text
副作用を伴わない操作の場合① >>> name_1 = 'aaa' # str型のイミュータブルなオブジェクト >>> id(name_1) 139720897350384 >>> name_1.replace('a', 'b') # nameとは別オブジェクトを生成する、副作用 のない操作 'bbb' >>> name_1 # 上記のreplaceでname値は変更されていないのでidはそのまま 'aaa' 16
Slide 17
Slide 17 text
副作用を伴わない操作の場合② >>> name_1 = 'aaa' # str型のイミュータブルなオブジェクト >>> name_2 = name_1 >>> name_1 = 'bbb' # nameは1行目とは別のオブジェクトになります。 >>> name_2 # str型はイミュータブルなのでname_2には影響はありません。 'aaa' 17
Slide 18
Slide 18 text
18 name name_2 オブジェク ト① name name_2 オブジェク ト① オブジェク ト② name = 'bbb'
Slide 19
Slide 19 text
副作用を伴わない操作の場合③ >>> list_1 = [1, 2, 3] # List型のミュータブルなオブジェクト >>> list_2 = list_1 + [4] # list_1の値が変わらないイミュータブルな操作 >>> list_2 [1, 2, 3, 4] >>> list_1 [1, 2, 3] 19
Slide 20
Slide 20 text
副作用を伴わない操作の場合④ >>> id(list_1) 140410856800704 >>> id(list_2) 140410884215232 20
Slide 21
Slide 21 text
副作用を伴う操作の場合① >>> list_1 = [1, 2, 3] # List型のミュータブルなオブジェクト >>> id(list_1) 139720897421120 >>> list_1.append(4) # list_1の値を変更する副作用を伴う処理 >>> list_1 [1, 2, 3, 4] >>> id(list_1) # ミュータブルなので値が変わりオブジェクトは同じまま 139720897421120 21
Slide 22
Slide 22 text
副作用を伴う操作の場合② >>> list_2 = list_1 >>> list_1.append(5) >>> list_1 [1, 2, 3, 4, 5] >>> list_2 # list_1とlist_2は同じオブジェクトを指したままなのでlist_2も 変更 [1, 2, 3, 4, 5] 22
Slide 23
Slide 23 text
list_2の値が変わらないようにするには copy.copyを使いましょう。 23 >>> list_1 = [1, 2, 3] >>> list_2 = copy.copy(list_1) >>> list_1.append(4) >>> list_1 [1, 2, 3, 4] >>> list_2 [1, 2, 3]
Slide 24
Slide 24 text
copy.copyを使うと何が起こるか 代入元の変数の値がコピーされたオブジェクトが渡されて 別のオブジェクトとなります。 24 >>> list_1 = [1, 2, 3] >>> list_2 = copy.copy(list_1) >>> id(list_1) 140594427010048 >>> id(list_2) 140594427023056
Slide 25
Slide 25 text
まとめ ● 副作用とは、オブジェクトの値を変更することです。 ● 副作用を伴う操作を許容しないのがイミュータブルなオブジェクト。 ● 副作用を伴う操作を許容するのがミュータブルなオブジェクト。 ● ミュータブルな型の変数を別の変数に代入したら 変数の変更が別の変数にも反映されます。 ● ミュータブルな変数を別の変数に代入したいならcopy.copyを使いましょう。 ご清聴ありがとうございました。 25
Slide 26
Slide 26 text
[おまけ] list_1とlist_2の値は何になるでしょうか? >>> def add_number(numbers_list: List[int], number: int) -> List[int]: ... numbers_list.append(number) ... return numbers_list >>> >>> list_1 = [1, 2, 3] >>> list_2 = add_number(l, 4) 26
Slide 27
Slide 27 text
list_2には値が変わってほしくなかったのに… >> # 正解は… >>> list_1 [1, 2, 3, 4] >>> list_2 [1, 2, 3, 4] 27
Slide 28
Slide 28 text
copy.copyで意図しない値の変化を防ぎましょう >>> def add_number(numbers_list: List[int], number: int) -> List[int]: ... added_list = copy.copy(numbers_list) ... added_list.append(number) ... return added_list 28