You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让list_odds随Champ对象的odds属性自动同步?

问题描述

我需要用random.choices(list_champs, weights=list_odds)根据概率选择Champion对象,因此要维护Champion对象列表list_champs和对应的概率列表list_odds。但修改list_champs中Champ对象的odds属性后,list_odds无法自动同步更新。

核心需求:

  • 频繁执行选择操作,性能优先,不想每次更新属性都重新生成整个list_odds
  • 不想手动同步对象属性与list_odds,希望list_odds能像dict.keys()的视图结构一样,自动跟随对象的odds属性变化

示例代码及运行结果如下:

import random

class Champ:
    def __init__(self, odds):
        self.odds = odds
    def __repr__(self):
        return f"Champ({self.odds=})"

# 创建两个Champ实例
champ1 = Champ(odds = 0.25)
champ2 = Champ(odds = 0.5)

# 生成对象列表和对应的权重列表
list_champs = [champ1, champ2]
list_odds = [champ.odds for champ in list_champs]

print(f"{list_champs=}")
print(f"{list_odds=}")

# 执行随机选择操作
random_champ = random.choices(list_champs, weights=list_odds)[0]

# 修改champ1的概率值
print("Changing odds : champ1.odds = 0.99")
champ1.odds = 0.99

# 期望list_odds能同步更新,但实际并未变化
print(f"{list_champs=}")
print(f"{list_odds=}")

# 此时随机选择的权重还是旧值
random_champ = random.choices(list_champs, weights=list_odds)[0]

运行输出:

list_champs=[Champ(self.odds=0.25), Champ(self.odds=0.5)]
list_odds=[0.25, 0.5]
Changing odds : champ1.odds = 0.99
list_champs=[Champ(self.odds=0.99), Champ(self.odds=0.5)]
list_odds=[0.25, 0.5]
解决方案

可以自定义一个权重视图类,它不存储固定的权重值,而是在需要时动态从对应的Champ对象中读取odds属性。这样既不用手动同步,也能保证每次使用时都是最新的权重,同时避免了重复生成列表的性能开销。

实现代码

import random

class Champ:
    def __init__(self, odds):
        self.odds = odds
    def __repr__(self):
        return f"Champ({self.odds=})"

class WeightsView:
    def __init__(self, champs_list):
        self.champs = champs_list
    
    # 实现__getitem__,让random.choices能正常访问元素
    def __getitem__(self, index):
        return self.champs[index].odds
    
    # 实现__len__,满足random.choices对权重序列的长度要求
    def __len__(self):
        return len(self.champs)

# 使用示例
champ1 = Champ(odds=0.25)
champ2 = Champ(odds=0.5)
list_champs = [champ1, champ2]
# 创建权重视图,而非固定列表
list_odds = WeightsView(list_champs)

print(f"{list_champs=}")
# 打印视图时可以手动转换为列表查看当前权重
print(f"当前权重: {[w for w in list_odds]}")

# 执行随机选择
random_champ = random.choices(list_champs, weights=list_odds)[0]

# 修改champ1的概率
print("Changing odds : champ1.odds = 0.99")
champ1.odds = 0.99

print(f"{list_champs=}")
# 再次查看权重,已经同步更新
print(f"当前权重: {[w for w in list_odds]}")

# 此时随机选择会使用新的权重
random_champ = random.choices(list_champs, weights=list_odds)[0]

运行结果

list_champs=[Champ(self.odds=0.25), Champ(self.odds=0.5)]
当前权重: [0.25, 0.5]
Changing odds : champ1.odds = 0.99
list_champs=[Champ(self.odds=0.99), Champ(self.odds=0.5)]
当前权重: [0.99, 0.5]

原理说明

  • WeightsView类仅持有Champ对象列表的引用,不存储固定权重值
  • 当random.choices访问权重序列元素时,__getitem__方法实时从对应Champ对象读取最新的odds属性
  • 实现__len__方法是为了满足random.choices对权重序列的长度校验要求
  • 这种方式性能开销极低,仅在实际需要权重值时才读取属性,避免了预先生成和更新列表的额外成本

内容的提问来源于stack exchange,提问作者Ernest Klimann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 10:17:50