nkj23
@nkj23 (Yuta Nakamura)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

発生させた乱数を確認する方法

解決したいこと

「random.sample」で発生させた乱数の結果がどうなっているのかを確認したいです。
以下のように「prefs_list」と「prefd_list」から「pref」に「random.sample」でランダム抽出し、それを「1:BrandNew」に代入し、これが含まれる「barnd_news」を用いて最終的に結果が出力されます。
そこで組み込んでしまった「1:BrandNew」の中身が知りたいのですが、最後に「print(pref)」を行なっても「1:BrandNew」に生成されたものとは別のリストが出力されてしまいます。実際に「1:BrandNew」で生成されたリストを確認するにはどうしたら良いのでしょうか。シード値の設定等、自分でも試してはみたのですが、よくわからないまま終わってしまいました。
ご教授いただけると幸いです。

該当するソースコード

prefs_list = ['A','B','C']
prefd_list = [1,2,3,4,5,6,7,8]

for i in range(10):
  pref = random.sample(prefs_list,3)
  brand_news = {
      1: BrandNew(pref),
      2: BrandNew(['A', 'B', 'C']),
      3: BrandNew(['B', 'A', 'C']),
      4: BrandNew(['B', 'A', 'C']),
      5: BrandNew(['A', 'C', 'B']),
      6: BrandNew(['C', 'A', 'B']),
      7: BrandNew(['A', 'B', 'C']),
      8: BrandNew(['B', 'A', 'C']),
  }
  
  departments = {
      'A': Department(random.sample(prefd_list,8), 10),
      'B': Department([1, 7, 4, 5, 3, 2, 8, 6], 10),
      'C': Department([5, 6, 7, 8, 1, 2, 3, 4], 10),
  }
 
 
  # 全て配属されるまで実行
  while len(xs := not_keeped_applicatns(brand_news, departments)) > 0:
      # 仮決定されてない応募者を処理対象者とする
      for x in xs:
          target_dpts = brand_news[x].pop_preference()
          departments[target_dpts].this_step_applicant = [x]
  print(i) 
  print(pref)      
  print('A',departments['A'].keep_members)
  print('B',departments['B'].keep_members)
  print('C',departments['C'].keep_members)
0

2Answer

めちゃくちゃ細かいんですが今後他の言語で「参照渡し」と出会ったときに混乱するとまずいので補足です。

4. その他の制御フローツール — Python 3.11.1 ドキュメント

関数を呼び出す際の実際の引数 (実引数) は、関数が呼び出されるときに関数のローカルなシンボルテーブル内に取り込まれます。そうすることで、実引数は 値渡し (call by value) で関数に渡されることになります

とあるように、pythonの引数は値渡しです。

2Like

https://qiita.com/nkj23/questions/c82e3c23fc47350e1938
こちらに関連する内容でしょうか?
本質問に記載のコードだけでは BrandNew(pref) などの詳細な動作が分からないので上記質問に関連する内容としての回答です。

BrandNew(pref) の中で preference に pref をコピーしていますが、これは参照渡しとなります。
参照渡し (と値渡し) については様々な解説記事ございますのでご検索ください。
参照渡しについてざっくり説明すると同じデータに対して別の変数名をつけるというものになります。
イメージとしてはAさんがBさんに教科書をみせてもらうといった感じでしょうか。
(AもBも教科書を見ることはできるが、教科書自体は同じもの)

従って、この時点で pref と brand_news[1].preference が同じデータを示すことになります。
その後、「仮決定されていない応募者を処理対象者とする」処理の中で brand_news[x].pop_preference() が実行され、ここで preference.pop(0) されています。
これにより brand_news[1].preference (= pref) が変更されているので最終的に print(pref) した際に異なるリストが表示される結果になります。

生成されたリストを確認したいということですので以下のどちらかで如何でしょうか。

  1. pref = random.sample(prefs_list,3) の実行直後など、pop_preference() が実行される前に print(pref) を実行することで pop(0) により変更される前に確認する
for i in range(10):
  pref = random.sample(prefs_list,3)
  print(pref)
  brand_news = {
  ...
  1. BrandNew の __init__ 内で self.preference = preference ではなく self.preference = preference.copy() にすることで参照渡しをやめる
class BrandNew:
    def __init__(self, preference: list):
        self.preference = preference.copy()
1Like

Comments

  1. @nkj23

    Questioner

    ご回答ありがとうございます。
    コードが不十分だったにも関わらず、doranko様の回答通りにいじってみたところうまく確認することができました。参照渡しについて色々調べて勉強してみました。
    すごく助かり、また勉強になりました。
    ありがとうございましたm(__)m
  2. ozwk様の補足を受けて私の方でも追記です。

    > そうすることで、実引数は 値渡し (call by value) で関数に渡されることになります (ここでの 値 (value) とは常にオブジェクトへの 参照(reference) をいい、オブジェクトの値そのものではありません)

    ということで、pythonの場合は「参照の値渡し」です。
    回答時にそのほうが分かりやすいかと思い「これは参照渡しとなります。」という表現をしてしまいましたが正確にはオブジェクトへの参照を値渡ししています。

Your answer might help someone💌