Python random模块随机选择不均的纯Python解决方案咨询
问题描述
我写了一个在聊天群里选「今日之星」的Python函数,但随机选择效果极差——比如8人群里有个成员连续56天没被选中。机器人每天凌晨1点左右重启,中午12点执行选星操作,怀疑是random.seed()的问题。能不能只用Python内置特性解决,不用random.org这类外部服务?
代码如下:
def send_sun(id): try: members = (vk_session.method('messages.getConversationMembers', {'peer_id': 2000000000 + id})['profiles']) num_of_members = len(members) if num_of_members == 1: send(id, "Хотела я выбрать из этой беседы солнышко, а выбирать-то не из кого, вы здесь один...") else: sun = random.choince(members)['id'] # 拼写错误:choince → choice sun_profile = vk_session.method('users.get', {'user_ids' : sun})[0] if(setting_interface.check(id, "send_sun")): send(id, "Солнышко сегодняшнего дня - [id" + str(sun_profile['id']) + "|" + sun_profile['first_name'] + " "+ sun_profile ['last_name'] + "]") return except: send(id, "Что-то не то с солнышком. Пожалуйста, проверьте, что у меня есть права администратора, попробуйте выключить эту функцию и включить снова (команды могу напомнить по команде: Ира, что ты умеешь?). Если проблема не исчезнет, сообщите моему создателю, пожалуйста")
解决方案
首先纠正代码里的低级错误:random.choince是拼写错误,应该改为random.choice,但这不是连续不选中的核心原因。
核心问题:机器人每日固定时间重启,默认情况下random模块用系统当前时间做种子。如果重启时间的时间戳精度不足,或者两次重启的时间戳重复,会导致每次生成的随机序列一致,进而出现某些成员长期不被选中的情况。
以下是几种纯Python内置特性的解决方法:
1. 使用系统级随机源替代默认随机器
直接用random.SystemRandom()类,它底层调用os.urandom()获取系统熵池的随机数据,随机性远强于默认的时间种子,且无需手动设置种子:
from random import SystemRandom # 初始化一次即可,放在机器人启动逻辑里 sys_random = SystemRandom() # 替换原代码中的random.choice sun = sys_random.choice(members)['id']
2. 用日期作为唯一种子
如果希望同一天重复调用时选同一个人,且每天的种子唯一,可以用当天日期的序数作为种子,彻底避免重启导致的种子重复:
from datetime import date import random # 在每日选星操作前设置种子 today = date.today() random.seed(today.toordinal()) # 执行选择 sun = random.choice(members)['id']
3. 记录历史实现轮询/加权选择
如果要彻底杜绝成员长期不被选中的情况,可以维护一个简单的历史记录,实现轮询机制(每个成员按顺序被选中):
import json import os from datetime import date # 读取群聊的选中历史 def get_sun_history(group_id): file_path = f"sun_history_{group_id}.json" if os.path.exists(file_path): with open(file_path, 'r') as f: return json.load(f) return {"last_index": -1, "last_date": str(date.today())} # 保存选中历史 def save_sun_history(group_id, data): file_path = f"sun_history_{group_id}.json" with open(file_path, 'w') as f: json.dump(data, f) def send_sun(id): try: members = vk_session.method('messages.getConversationMembers', {'peer_id': 2000000000 + id})['profiles'] num_of_members = len(members) if num_of_members == 1: send(id, "Хотела я выбрать из этой беседы солнышко, а выбирать-то не из кого, вы здесь один...") return today = str(date.today()) history = get_sun_history(id) # 新的一天则轮询到下一个成员 if history['last_date'] != today: next_index = (history['last_index'] + 1) % num_of_members sun = members[next_index]['id'] # 更新历史记录 history['last_index'] = next_index history['last_date'] = today save_sun_history(id, history) else: # 当天已选过,复用结果 sun = members[history['last_index']]['id'] sun_profile = vk_session.method('users.get', {'user_ids': sun})[0] if setting_interface.check(id, "send_sun"): send(id, f"Солнышко сегодняшнего дня - [id{sun_profile['id']}|{sun_profile['first_name']} {sun_profile['last_name']}]") except Exception as e: print(f"选星出错:{e}") send(id, "Что-то не то с солнышком. Пожалуйста, проверьте, что у меня есть права администратора, попробуйте выключить эту функцию и включить снова (команды могу напомнить по команде: Ира, что ты умеешь?). Если проблема не исчезнет, сообщите моему создателю, пожалуйста")
内容的提问来源于stack exchange,提问作者Anya Siyankovskaya
相关产品推荐
相关产品推荐

