鱼C论坛

 找回密码
 立即注册
查看: 175|回复: 22

[已解决]为什么逻辑上可以,但实际会报错呢?

[复制链接]
发表于 7 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
第一种方式会报错:pop index out of range
但是把  len(待打乱序列)直接放到random.randint中就不会报错
#这样会报错#
序列长度 = len(待打乱序列)
随机数 = random.randint(0,序列长度-1)
弹出的数据 = 待打乱序列.pop(随机数)
#这样不会#
随机数 = random.randint(0,len(待打乱序列)-1)
弹出的数据 = 待打乱序列.pop(随机数)


这是为什么呢
import random
#这个代码跑不起来#
def 洗牌算法(待打乱数据,打乱次数 = 1):
    for i in range(打乱次数):#一共完全打乱几次#
        待打乱序列 = list(待打乱数据)#先把字符串转化为列表#
        result = []
        序列长度 = len(待打乱序列)

        while 待打乱序列:#分步开始打乱序列#
            

            result.append(弹出的数据)
        print(f"第{i+1}次打乱后的结果是:{''.join(result)}")
    print("最终的结果是:",''.join(result))





    
待打乱数据 = input("请输入需要打乱的数据:")
n = int(input("请输入需要打乱的次数:"))
洗牌算法(待打乱数据,打乱次数 = n)
import random
#这个是能跑起来的#
def 洗牌算法(待打乱数据,打乱次数 = 1):
    for i in range(打乱次数):#一共完全打乱几次#
        待打乱序列 = list(待打乱数据)#先把字符串转化为列表#
        result = []
        while 待打乱序列:#分步开始打乱序列#
            
            随机数 = random.randint(0,len(待打乱序列)-1)
            弹出的数据 = 待打乱序列.pop(随机数) 
            result.append(弹出的数据)
        print(f"第{i+1}次打乱后的结果是:{''.join(result)}")
    print("最终的结果是:",''.join(result))





    
待打乱数据 = input("请输入需要打乱的数据:")
n = int(input("请输入需要打乱的次数:"))
洗牌算法(待打乱数据,打乱次数 = n)
        
最佳答案
7 天前
因为第一种你把长度写死了,删除完元素,长度没更新
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 7 天前 | 显示全部楼层
首先,让我们分析代码报错的原因。这里的关键点在于每次从 `待打乱序列` 中 `pop` 一个元素后,序列的长度会减少。如果在开始时计算一次 `序列长度` 并存储在一个变量中,那么这个值在后续不会改变。而 `随机数 = random.randint(0,序列长度-1)` 仍然依赖这个初始的长度值,可能导致 `pop` 时访问超过当前序列长度的下标,从而抛出 "pop index out of range" 错误。

而在第二种实现中,每次循环计算 `len(待打乱序列)` 的长度,这确保了获取的随机索引始终在当前可用的范围内,因此不会超出范围。

解决方法:  
应在循环中使用 `len(待打乱序列)` 确保每次获取的随机数都在正确的范围内。

建议代码如下:
import random

def 洗牌算法(待打乱数据, 打乱次数=1):
    for i in range(打乱次数):
        待打乱序列 = list(待打乱数据)
        result = []

        while 待打乱序列:
            随机数 = random.randint(0, len(待打乱序列)-1)
            弹出的数据 = 待打乱序列.pop(随机数)
            result.append(弹出的数据)

        print(f"第{i+1}次打乱后的结果是:{''.join(result)}")
    print("最终的结果是:", ''.join(result))

待打乱数据 = input("请输入需要打乱的数据:")
n = int(input("请输入需要打乱的次数:"))
洗牌算法(待打乱数据, 打乱次数=n)

用这种方法,每次生成的随机数都是在当前 `待打乱序列` 限定的范围内,因此不会产生超出范围的错误。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
我迷茫了,逻辑上不是一样的么?就是分成了几步,多了个变量啊?为什么会超范围呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
llpayr 发表于 2025-01-10 16:33
我迷茫了,逻辑上不是一样的么?就是分成了几步,多了 ...


问题的关键在于变量 `序列长度` 的使用时机。

当你在循环外计算 `序列长度 = len(待打乱序列)` 时,这个值在整个循环过程中保持不变,意味着随着 `待打乱序列` 的元素逐步被 `pop` 出来,这个固定的 `序列长度` 不再表示实际可用的索引范围。最终,可能会导致 `random.randint(0,序列长度-1)` 生成一个大于当前序列长度的索引,进而导致 "pop index out of range" 错误。

而在第二种实现中,每次 `pop` 之前都重新计算 `len(待打乱序列)`,这样 `random.randint` 调用时的范围会动态调整,以确保生成的索引始终在当前列表的实际范围之内。因此不会产生超出范围的问题。

总之,问题并不是变量个数的问题,而在于这个变量在程序运行过程中是否反映了当前的实际情况。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
不是中文变量的原因,我用了英文变量改了一遍,但还是会报错
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
llpayr 发表于 2025-01-10 16:35
不是中文变量的原因,我用了英文变量改了一遍,但还是 ...


报错与是否使用中文变量无关,而与程序中变量的动态更新有关。让我们再解释一下这个问题:

为了帮助理解,来看以下代码片段:

错误用法:
length = len(sequence)
index = random.randint(0, length - 1)
element = sequence.pop(index)

在这个代码片段中,`length` 在循环开始时被固定地计算了一次。如果紧接着的几个 `pop` 操作显著减少了 `sequence` 的长度,随后的 `random.randint(0, length - 1)` 仍然使用最初固定的 `length` 范围,这可能导致索引超出当前实际范围。

正确用法:
index = random.randint(0, len(sequence) - 1)
element = sequence.pop(index)

在这里,每次 `pop` 操作之前都会重新计算 `len(sequence)`。因此,即便 `sequence` 的长度每次 `pop` 时发生变化,`random.randint(0, len(sequence) - 1)` 也能确保索引始终在当前有效范围内。

综上所述,问题并不是在于使用的变量名是否为中文,而是在于变量 `length` 的计算时机。如果在每次需要时动态计算长度,就能避免 “index out of range” 的问题。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
import random
cards = ["♦1", "♦2", "♦3", "♦4", "♦5", "♦6", "♦7", "♦8", "♦9", "♦10", "♦J", "♦Q", "♦K",
         "♥1", "♥2", "♥3", "♥4", "♥5", "♥6", "♥7", "♥8", "♥9", "♥10", "♥J", "♥Q", "♥K",
         "♣1", "♣2", "♣3", "♣4", "♣5", "♣6", "♣7", "♣8", "♣9", "♣10", "♣J", "♣Q", "♣K",
         "♠1", "♠2", "♠3", "♠4", "♠5", "♠6", "♠7", "♠8", "♠9", "♠10", "♠J", "♠Q", "♠K",
         "☀", "🌙"]

def 洗牌算法(待打乱数据,打乱次数 = 1):
    for i in range(打乱次数):#一共完全打乱几次#
        cards_new_洗牌 = []
        while 待打乱数据:#分步开始打乱序列#
            随机数 = random.randint(0,len(待打乱数据)-1)
            弹出的数据 = 待打乱数据.pop(随机数)
            cards_new_洗牌.append(弹出的数据)
    return cards_new_洗牌


   
def 选地主和发牌():
    player1 = input("请输入第一位玩家姓名:")
    player2 = input("请输入第二位玩家姓名:")
    player3 = input("请输入第三位玩家姓名:")
    地主 = random.sample([player1,player2,player3],1)
    print(f"地主是:{地主}")

    cards_new = 洗牌算法(cards,3)
    cards_player1 = []
    cards_player2 = []
    cards_player3 = []
    for i in range(17):
        cards_player1.append(cards_new.pop())
        cards_player2.append(cards_new.pop())
        cards_player3.append(cards_new.pop())
    if 地主 == player1:
        cards_player1 = cards_player1 +cards_new
    elif 地主 == player2:
        cards_player2 = cards_player2 +cards_new
    else:
        cards_player3 = cards_player3 +cards_new
    print(f"{player1}拿到的牌是:{cards_player1}")
    print(f"{player2}拿到的牌是:{cards_player2}")
    print(f"{player3}拿到的牌是:{cards_player3}")



        
选地主和发牌()

为什么
return cards_new_洗牌 后
cards_new = 洗牌算法(cards,3)
caras_new 仍然是空的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
llpayr 发表于 2025-01-10 17:36
import random
cards =

def 洗牌算法(待打乱数据 ...


出现这个问题的原因是代码中有些地方未正确初始化列表,导致 `cards_new_洗牌` 和其他一些列表为空。以下是修正后的代码,确保列表在使用前已正确初始化:
import random

# 定义一副扑克牌,这里假设你有一个完整的扑克牌列表
cards = ['A', '2', '3', ..., 'K', '红桃A', '红桃2', ..., '黑桃K']

def 洗牌算法(待打乱数据, 打乱次数=1):
    for i in range(打乱次数):
        cards_new_洗牌 = []  # 初始化为空列表
        temp_data = list(待打乱数据)  # 创建待打乱数据的副本,以免直接改变原始数据
        while temp_data:
            随机数 = random.randint(0, len(temp_data) - 1)
            弹出的数据 = temp_data.pop(随机数)
            cards_new_洗牌.append(弹出的数据)
    return cards_new_洗牌

def 选地主和发牌():
    player1 = input("请输入第一位玩家姓名:")
    player2 = input("请输入第二位玩家姓名:")
    player3 = input("请输入第三位玩家姓名:")
    地主 = random.choice([player1, player2, player3])
    print(f"地主是: {地主}")

    cards_new = 洗牌算法(cards, 3)
    cards_player1 = []
    cards_player2 = []
    cards_player3 = []

    for i in range(17):
        cards_player1.append(cards_new.pop())
        cards_player2.append(cards_new.pop())
        cards_player3.append(cards_new.pop())

    if 地主 == player1:
        cards_player1 = cards_player1 + cards_new
    elif 地主 == player2:
        cards_player2 = cards_player2 + cards_new
    else:
        cards_player3 = cards_player3 + cards_new

    print(f"{player1}拿到的牌是: {cards_player1}")
    print(f"{player2}拿到的牌是: {cards_player2}")
    print(f"{player3}拿到的牌是: {cards_player3}")

选地主和发牌()

注意事项:
1. 确保在 `洗牌算法` 中每次循环时初始化 `cards_new_洗牌` 为一个空列表。
2. 在函数内创建 `待打乱数据` 的副本以避免直接改变传入的 `cards` 列表。
3. 使用 `random.choice` 来选择 `地主`。

这样做可以确保 `cards_new` 被正确赋值,并且不会是空的。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层    本楼为最佳答案   
因为第一种你把长度写死了,删除完元素,长度没更新
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
给个最佳呗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
FishC 发表于 2025-1-10 17:38
出现这个问题的原因是代码中有些地方未正确初始化列表,导致 `cards_new_洗牌` 和其他一些列表为空。以 ...

还是不对,还是空的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
llpayr 发表于 2025-01-10 18:04
FishC 发表于 2025-1-10 17:38
出现这个问题的原因是 ...


好的,我们来一步步检查代码。确保所有的列表都已经正确初始化了,并在函数中正确地传递和使用。

以下是修正后的代码,确保 `cards_new_洗牌` 和其他所有涉及到的列表正确声明和使用:
import random

# 假设有一副完整的扑克牌列表
cards = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'] * 4 + ['小王', '大王']

def 洗牌算法(待打乱数据, 打乱次数=1):
    for _ in range(打乱次数):
        cards_new_洗牌 = []  # 初始化为空列表
        temp_data = list(待打乱数据)  # 创建待打乱数据的副本
        while temp_data:
            随机数 = random.randint(0, len(temp_data) - 1)
            弹出的数据 = temp_data.pop(随机数)
            cards_new_洗牌.append(弹出的数据)
    return cards_new_洗牌

def 选地主和发牌():
    player1 = input("请输入第一位玩家姓名:")
    player2 = input("请输入第二位玩家姓名:")
    player3 = input("请输入第三位玩家姓名:")
    地主 = random.choice([player1, player2, player3])
    print(f"地主是: {地主}")

    cards_new = 洗牌算法(cards, 3)

    # 初始化玩家的牌
    cards_player1 = []
    cards_player2 = []
    cards_player3 = []

    for _ in range(17):
        cards_player1.append(cards_new.pop())
        cards_player2.append(cards_new.pop())
        cards_player3.append(cards_new.pop())

    # 分配地主的牌
    if 地主 == player1:
        cards_player1 += cards_new
    elif 地主 == player2:
        cards_player2 += cards_new
    else:
        cards_player3 += cards_new

    print(f"{player1}拿到的牌是: {cards_player1}")
    print(f"{player2}拿到的牌是: {cards_player2}")
    print(f"{player3}拿到的牌是: {cards_player3}")

选地主和发牌()

关键点:
1. 初始化`cards_new_洗牌`为一个空列表,每次要生成新顺序时。
2. 确保每个玩家的牌在发牌前初始化为空列表。
3. `random.choice` 的参数应为列表 `[player1, player2, player3]`。
4. 在 `洗牌算法` 函数中,应使用局部的 `temp_data` 来操作序列,以免修改原始 `cards`。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
你第一个程序里面把 len 的操作放在循环的外面了。 pop 函数会不断的弹出元素,列表长度不断地减少,从 len-1 一直到 0,但这个列表长度的变量还没有更新,如果随机的数大于了列表的长度就会报错。
顺便说一下,不建议使用中文作变量名。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 7 天前 | 显示全部楼层
列表的 pop 方法会弹出元素。
>>> x = ['a', 'b', 'c', 'd']
>>> x.pop(1)
'b'
>>> x
['a', 'c', 'd']
>>> x.pop(2)
'd'
>>> x
['a', 'c']
>>> 
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
llpayr 发表于 2025-1-10 18:04
还是不对,还是空的

不是戈门,我都告诉你了,你看看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 6 天前 | 显示全部楼层
某一个“天” 发表于 2025-1-10 17:49
因为第一种你把长度写死了,删除完元素,长度没更新

感谢,我理解了  谢谢大佬
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 6 天前 | 显示全部楼层
tommyyu 发表于 2025-1-10 18:52
你第一个程序里面把 len 的操作放在循环的外面了。 pop 函数会不断的弹出元素,列表长度不断地减少,从 len ...

谢谢 理解了 十分感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 6 天前 | 显示全部楼层
FishC 发表于 2025-1-10 18:04
好的,我们来一步步检查代码。确保所有的列表都已经正确初始化了,并在函数中正确地传递和使用。

以 ...

不行,还是报错
pop from empty list
  File "D:\Python\练习\044.1 斗地主发牌.py", line 32, in 选地主和发牌
    cards_player1.append(cards_new.pop(0))
                         ^^^^^^^^^^^^^^^^
  File "D:\Python\练习\044.1 斗地主发牌.py", line 48, in <module>
    选地主和发牌()
IndexError: pop from empty list
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 6 天前 | 显示全部楼层
llpayr 发表于 2025-01-11 12:07
FishC 发表于 2025-1-10 18:04
好的,我们来一步步检 ...


根据您描述的错误信息,在试图从 `cards_new` 列表中 `pop` 一个元素时失败,说明 `cards_new` 在某些情况下可能没有正确填充。我们需要确保 `洗牌算法` 函数的逻辑正确实现,来正确生成新顺序的牌。

请检查以下修正过的代码:
import random

# 假设有一副完整的扑克牌列表
cards = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'] * 4

def 洗牌算法(待打乱数据, 打乱次数=1):
    for _ in range(打乱次数):
        cards_new_洗牌 = []  # 初始化为空列表
        temp_data = list(待打乱数据)  # 创建待打乱数据的副本
        while temp_data:
            随机数 = random.randint(0, len(temp_data) - 1)
            弹出的数据 = temp_data.pop(随机数)
            cards_new_洗牌.append(弹出的数据)
    return cards_new_洗牌

def 选地主和发牌():
    player1 = input("请输入第一位玩家姓名:")
    player2 = input("请输入第二位玩家姓名:")
    player3 = input("请输入第三位玩家姓名:")
    地主 = random.choice([player1, player2, player3])
    print(f"地主是: {地主}")

    cards_new = 洗牌算法(cards, 3)

    # 初始化玩家的牌
    cards_player1 = []
    cards_player2 = []
    cards_player3 = []

    for _ in range(17):
        # 确保 cards_new 还有牌可以 pop
        if cards_new:
            cards_player1.append(cards_new.pop(0))
        if cards_new:
            cards_player2.append(cards_new.pop(0))
        if cards_new:
            cards_player3.append(cards_new.pop(0))

    # 分配地主的牌
    if cards_new:
        if 地主 == player1:
            cards_player1 += cards_new
        elif 地主 == player2:
            cards_player2 += cards_new
        else:
            cards_player3 += cards_new

    print(f"{player1}拿到的牌是: {cards_player1}")
    print(f"{player2}拿到的牌是: {cards_player2}")
    print(f"{player3}拿到的牌是: {cards_player3}")

选地主和发牌()

请确认修改后的代码中:

1. `cards` 列表中的初始内容按您的需求正确设置(示例使用标准扑克牌,四套,每套13张)。
2. `cards_new` 确实从 `洗牌算法` 返回已打乱的完整牌序列。
3. 在发牌时,确保检查 `cards_new` 在 `pop` 前有足够的牌。

如果需要更多帮助,请确保提供完整的代码和具体的需求描述。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 6 天前 | 显示全部楼层
FishC 发表于 2025-1-11 12:10
根据您描述的错误信息,在试图从 `cards_new` 列表中 `pop` 一个元素时失败,说明 `cards_new` 在某些 ...

cards 本身就是列表的形式
为什么在洗牌算法中不能直接写
temp_data = 待打乱数据
而要写
temp_data = list(待打乱数据)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-17 08:55

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表