【Python】任意の数の初期データリストを生成する

python-logo Python

「初期データとしてユーザーを10人生成したい」というときの
実装方法と注意点について説明する。

任意の数のデータを生成する

まずはクラスから生成したインスタンスではなく、
通常の数値や文字データの場合。

# 「1」というデータを5つ生成する
number_list: list[int] = [1] * 5
print(number_list)

# 実行結果
[1, 1, 1, 1, 1]

リストに対して* 5 を記載することで、そのデータを5個複製できる。

クラスからインスタンスを生成する場合(注意)

例えば以下のようなユーザークラスから生成したインスタンスを、3人分作りたいとする。

from dataclasses import dataclass

@dataclass
class User:
    name: str

先程と同じように、以下のコードで生成してしまうとNG。

# "hoge"という名前のユーザーを3人分生成する
user_list: list[User] = [User("hoge")] * 3
print(user_list)

# 全員分のデータを出力する
for user in user_list:
    print(f"id={id(user)}  user_name={user.name}")

# 実行結果
[User(name='hoge'), User(name='hoge'), User(name='hoge')]
id=4472590608  user_name=hoge
id=4472590608  user_name=hoge
id=4472590608  user_name=hoge

どこがNGポイントかと言うと、インスタンスのIDが全て同一のものになってしまっている点だ。
この場合、仮にuser_list[0]のデータを変更した場合、同時にuser_list[1]user_list[2]のデータも同じように変更されてしまう。

user_list: list[User] = [User("hoge")] * 3
print(user_list)

for user in user_list:
    print(f"id={id(user)}  user_name={user.name}")

user_list[0].name = "fuga"
print("user_list[0]の名前を「fuga」に変更しました")

for user in user_list:
    print(f"id={id(user)}  user_name={user.name}")

# 実行結果
[User(name='hoge'), User(name='hoge'), User(name='hoge')]
id=4439085520  user_name=hoge
id=4439085520  user_name=hoge
id=4439085520  user_name=hoge
user_list[0]の名前を「fuga」に変更しました
id=4439085520  user_name=fuga
id=4439085520  user_name=fuga
id=4439085520  user_name=fuga

どうしたらよいか?

これを解決するためには、以下のように書けばOK。

# リスト内包表記で、for文を使って「User("hoge")」を3回実行する
user_list: list[User] = [User("hoge") for _ in range(0, 3)]

print(user_list)
for user in user_list:
    print(f"id={id(user)}  user_name={user.name}")

# 実行結果
# 全てインスタンスIDが異なる状態で生成されていることが分かる
[User(name='hoge'), User(name='hoge'), User(name='hoge')]
id=4441985296  user_name=hoge
id=4441983312  user_name=hoge
id=4441983248  user_name=hoge

まとめ

  • 数値や文字列をたくさん生成する場合は気にせず簡単な表記でOK
  • クラスからインスタンスを生成する場合は、しっかりと都度インスタンスを生成するような実装が必要
タイトルとURLをコピーしました