命令引发异常:TypeError: unhashable type: 'list' when updates my database

时间:2021-03-10 21:02:25

标签: python discord discord.py bots

我的整个代码:

from discord.ext.commands import Bot, CheckFailure, has_role
import discord
import os
import random
from replit import db
from keep_alive import keep_alive
from statistics import mode
from operators import embeds
from datetime import date


#embed preset
'''
embed = discord.Embed(title="title", description="desc", color=PURPLE)
embed.set_author(name="Jäger Bot", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
embed.add_field(name="name", value="value", inline=True)
embed.set_footer(text="requested by " + authormention + "| " + send_date)
await ctx.send(embed=embed)
'''

bot = Bot(command_prefix="j!", help_command=None)

# bot ready and activity
@bot.event
async def on_ready():
  print("Bot started")
  game = discord.Game("with Jäger")
  await bot.change_presence(status=discord.Status.online, activity=game)
# --------------------

PURPLE = 0x800080
STAFF_ROLE_ID = 817476654297383002
SOTW_ROLE_ID = 817458661982994463
FORMER_SOTW_ROLE_ID = 817030310663028736
JAGER_ROLE_ID = 818950349016137739

today = date.today()

global is_voting
is_voting = False

global send_date
send_date = today.strftime("%d-%m-%Y")

#update db
@bot.event
async def update_db(key, value):
  if key in db.keys():
      old_value = db[key]
      old_value.append(value)
      db[key] = old_value
  else:
      db[key] = [value]
#keys:
#nominating_perons ppl who have nominated
#nominated_persons ppl who have been nominated
#voting_perons ppl who have voted
#voted_persons ppl who have been voted for

#----commands----

#help
@bot.command()
async def help(ctx ,category=None):
  print("command: help")
  staff_category = "staff"
  sotw_category = "sotw"
  misc_category = "misc"
  if category is None:
    print("no category")
    embed = discord.Embed(title="Select a category with `j!help \"category\"`", description="Prefix = j!", color=PURPLE)
    embed.set_author(name="Jäger Bot | Help menu", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
    embed.add_field(name="Categories:", value="`staff` `sotw` `misc`", inline=True)
    embed.set_footer(text="Made by ZoutigeWolf#0002 | Big thx to gang#5039 for helping")
    await ctx.send(embed=embed)
  else:
    if category == staff_category:
      print("staffhelp")
      staff = discord.Embed(title="Staff commands", description="prefix = j!", color=PURPLE)
      staff.set_author(name="Jäger Bot | Help menu", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
      staff.add_field(name="startvote", value="Starts the voting process", inline=False)
      staff.add_field(name="finishvote", value="Finishes the voting process", inline=False)
      staff.add_field(name="list <key> | debug only", value="Shows all the items in a specific list", inline=False)
      staff.add_field(name="clear <key> | debug only", value="Clears all the items in a specific list", inline=False)
      staff.add_field(name="ph <key> | debug only", value="Adds a `place_holder` to a specific list", inline=False)
      staff.set_footer(text="Made by ZoutigeWolf#0002 | Big thx to gang#5039 for helping")
      await ctx.send(embed=staff)
    else:
      if category == sotw_category:
        print("sotwhelp")
        sotw = discord.Embed(title="Sotw commands", description="prefix = j!", color=PURPLE)
        sotw.set_author(name="Jäger Bot | Help menu", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
        sotw.add_field(name="nominate <member>", value="Nominate a member", inline=False)
        sotw.add_field(name="vote <member>", value="Vote for a member", inline=False)
        sotw.set_footer(text="Made by ZoutigeWolf#0002 | Big thx to gang#5039 for helping")
        await ctx.send(embed=sotw)
      else:
        if category == misc_category:
          print("mischelp")
          misc = discord.Embed(title="Misc commands", description="prefix = j!", color=PURPLE)
          misc.set_author(name="Jäger Bot | Help menu", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
          misc.add_field(name="quote", value="A random siege operator quote", inline=False)
          misc.add_field(name="profile <operator>", value="Shows the profile of the specified siege operator", inline=True)
          misc.add_field(name="shoot <member>", value="Shoot someone", inline=False)
          misc.add_field(name="sexy <member>", value="Shows how sexy someone is", inline=False)
          misc.set_footer(text="Made by ZoutigeWolf#0002 | Big thx to gang#5039 for helping")
          await ctx.send(embed=misc)
        else:
          print("wrong category")
          embed = discord.Embed(title="Select a category with `j!help \"category\"`", description="Prefix = j!", color=PURPLE)
          embed.set_author(name="Jäger Bot | Help menu", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
          embed.add_field(name="Categories:", value="`staff` `sotw` `miscellaneous`", inline=True)
          embed.set_footer(text="Made by ZoutigeWolf#0002 | Big thx to gang#5039 for helping")
          await ctx.send(embed=embed)
#help end

#SOTW
#nominate
@bot.command()
async def nominate(ctx, nominatedperson: discord.Member):
  print("command: nominate")
  print(nominatedperson)
  nominated_person = nominatedperson.mention
  nominating_person = ctx.author.mention
  former_sotw_role = discord.utils.get(ctx.guild.roles, id=FORMER_SOTW_ROLE_ID)
  if not is_voting:
    print("is_voting was false")
    nominated_persons = db["nominated_persons"]
    nominating_persons = db["nominating_persons"]
    if nominating_person not in nominating_persons:
      print("nominating person wasnt in nominating persons")
      if nominated_person in nominated_persons:
        print("nominated_person was in nominated_persons")
        await ctx.send("That member has already been nominated!")
      else:
        print("nominated_person wasnt in nominated_persons")
        former_sotw_role = discord.utils.get(ctx.guild.roles, id=FORMER_SOTW_ROLE_ID)
        if former_sotw_role in nominatedperson.roles:
          print("nominated_person was former sotw")
          await ctx.send("That member has already been SOTW this year!")
        else:
          print("nominated_person wasnt former sotw")
          embed = discord.Embed(title="Member nominated:", description=nominated_person, color=PURPLE)
          embed.set_author(name="Jäger Bot", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
          embed.add_field(name="By:", value=nominating_person, inline=True)
          embed.set_footer(text=send_date)
          print(nominated_persons)
          await update_db(nominated_persons, nominated_person)
          await update_db(nominating_persons, nominating_person)
          await ctx.send(embed=embed)
    else:
      print("nominating_person was in nominating_persons")
      await ctx.send("You already nominated someone")
  else:
    print("is_voting was true")
    await ctx.send("You can't nominate while we are voting for the next SOTW!")
#nominate end
#SOTW end

#insert place_holder
@bot.command()
@has_role(STAFF_ROLE_ID)
async def ph(ctx, key):
  print("command: ph")
  await update_db(key, "place_holder")
  await ctx.send("Placeholder has been added to " + key)

@ph.error
async def ph_error(ctx, error):
  if isinstance(error, CheckFailure):
    await ctx.send("Only staff members can use this command")
#insert place_holder end

#list
@bot.command()
@has_role(STAFF_ROLE_ID)
async def list(ctx, to_list):
  print("command: list")
  if to_list in db.keys():
    requester = ctx.author
    requestermention = str(requester)
    items = db[to_list]
    embed = discord.Embed(title="List", description=to_list, color=PURPLE)
    embed.set_author(name="Jäger Bot", icon_url="https://cdn.discordapp.com/avatars/816636186323189780/019dbb41d6f5b301c1fce6980d487f23.webp?size=128")
    embed.add_field(name="Items:", value=items, inline=True)
    embed.set_footer(text="requested by " + requestermention + " | " + send_date)
    await ctx.send(embed=embed)
  else:
    await ctx.send("That list doesn't exist")

@list.error
async def list_error(ctx, error):
  if isinstance(error, CheckFailure):
    await ctx.send("Only staff members can use this command")
#list end

#list keys
@bot.command()
async def keys(ctx):
  allkeys = db.keys()
  await ctx.send(allkeys)
#list keys end

#clear
@bot.command()
@has_role(STAFF_ROLE_ID)
async def clear(ctx, to_clear):
  print("command: clear")
  str_userid = ctx.author.id
  str_zoutigewolfid = "298516275322290188"
  userid = int(str_userid)
  zoutigewolfid = int(str_zoutigewolfid)
  if userid == zoutigewolfid:
    if to_clear in db.keys():
      del db[to_clear]
      await ctx.send("List " + to_clear + " has been cleared")
    else:
      await ctx.send("That list doesn't exist")
  else:
    await ctx.send("Only my daddy Wolf can use this command!")

@clear.error
async def clear_error(ctx, error):
  if isinstance(error, CheckFailure):
    await ctx.send("Only staff members can use this command")
#clear end

#quote
# preset {"title": "", "description": ""},
quotes_list = [
{"title": "A really big fucking hole coming right up!", "description": "Jordan 'Thermite' Trace"},
{"title": "Pass those plates around!", "description":"Julien 'Rook' Nizan"},
{"title": "You can stop worrying about grenades now!", "description": "Marius 'Jäger' Streicher"},
{"title": "if it runs on batteries, I'll see it!", "description": "Monica 'IQ' Weiss"},
{"title": "Fookin' laser sights!", "description": "Mike 'Thatcher' Baker"},
{"title": "Toxic babes are in position!", "description": "James 'Smoke' Porter"},
{"title": "Jammah in position!", "description": "Mark 'Mute' R. Chandar"},
{"title": "EDD primed, let them come!", "description": "Maxim 'Kapkan' Basuda"},
{"title": "Mine flying out!", "description": "Elżbieta 'Ela' Bosak"},
{"title": "You're mine bloody asshole!", "description": "Taina 'Caveira' Pereira"},
{"title": "Malbodan haengdong-iji (말보단 행동이지)", "description": "Chul 'Vigil' Kyung Hwa"},
{"title": "Launching override!", "description": "Grace 'Dokkaebi' Nam"},
{"title": "Camera in position!", "description": "Meghan 'Valkyrie' J. Castellano"},
{"title": "As my friend would say: A really big fucking hole coming right up.", "description": "Yumiko 'Hibana' Imagawa"},
{"title": "Big brother coming in for overwatch!", "description": "Olivier 'Lion' Flament"},
{"title": "Time for a wakeup call", "description": "Grace 'Dokkaebi' Nam"},
{"title": "No runnin' in the halls!", "description": "Morowa 'Clash' Evans"},
{"title": "LMG mounted and loaded!", "description": "Alexsandr 'Tachanka' Senaviev, RIP old tachanka"},
{"title": "Rtila active!", "description": "Jalal 'Kaid' El Fassi"},
{"title": "Now you see me, now you don't!", "description": "Elena 'Mira' María Álvarez"},
{"title": "Why do it yourself when robots do it better?", "description": "Masaru 'Echo' Enatsu"},
{"title": "Bullseye, got us a drone", "description": "Max 'Mozzie' Goose"},
]

@bot.command()
async def quote(ctx):
  requester = ctx.author
  requestermention = str(requester)
  random_index = random.randint(0,21)
  quote = quotes_list[random_index]
  embed = discord.Embed(**quote, color=PURPLE)
  embed.set_footer(text="Requested by " + requestermention + " | " + send_date)
  await ctx.send(embed=embed)
#quote end

#operator profile
@bot.command()
async def profile(ctx, operator_name):
  await ctx.send(embed=embeds[operator_name])
#operator profile end

#sexy
@bot.command()
async def sexy(ctx, person: discord.Member):
  jager_role = discord.utils.get(ctx.guild.roles, id=JAGER_ROLE_ID)
  sexyperson = person.mention
  if jager_role in person.roles:
    print("person was jager")
    embed = discord.Embed(title="Sexy meter", description="Lord Jäger is 69420% sexy", color=PURPLE)
    await ctx.send(embed=embed)
  else:
    print("person wasnt jager")
    outputint = random.randint(0,100)
    output = str(outputint)
    embed = discord.Embed(title="Sexy meter", description=sexyperson + " is " + output + "% sexy", color=PURPLE)
    await ctx.send(embed=embed)
#sexy end

#gun list
guns_list = [
  "MP5",
  "M4",
  "AK-47",
  "MP7",
  "SCAR-L",
  "Desert Eagle",
  "MP5K",
  "AUG A2",
  "M249",
  "AR15"
]

#title list
title_list = [
  "Elimination",
  "Homicide",
  "Assasination",
  "Drive-by",
  "Sniped",
  "Popped",
  "Capped",
  "No-scoped",
]
#shoot
@bot.command()
async def shoot(ctx, person: discord.Member):
  print("command: shoot")
  shooter = ctx.author.mention
  shotperson = person.mention
  shooterid = ctx.author.id
  shotpersonid = person.id
  randomnumber = random.randint(0,9)
  randomgun = guns_list[randomnumber]
  randomtitlenumber = random.randint(0,7)
  title = title_list[randomtitlenumber]
  if shooterid != shotpersonid:
    embed = discord.Embed(title=title, description=shooter + " shot " + shotperson + " with " + randomgun, color=PURPLE)
    await ctx.send(embed=embed)
  else:
    await ctx.send("Shooting yourself is a very dumb idea")
#shoot end

#anti nword
racist_words = [
    "nigga",
    "niggas",
    "nigger",
    "niggers",
    "/Vigga",
    "/Viggas",
    "/Vigger",
    "/Viggers",
    "niga",
    "nega",
    "negga",
    "nibba",
    "/vigga",
    "/viggas",
    "/vigger",
    "/viggers",
]

# racist detector 9000
"""
@bot.event
async def on_message(msg):
    if any(word in msg.content for word in racist_words):
        print("someone said the n word")
        await msg.channel.send(msg.author.mention + " did you just seriously say the n-word?")
        await msg.channel.send("Not poggers bro, not poggers")
        await msg.channel.send(f"<@&{STAFF_ROLE_ID}> come get this bitch")
        await msg.delete()
        await bot.process_commands(msg)
"""
#racist end
#commands end

keep_alive()
bot.run(os.getenv("TOKEN"))

当我执行命令 j!nominate @discord 时,它会给出错误“命令引发异常:TypeError: unhashable type: 'list'”但不记得对任何列表进行哈希处理。有人可以告诉我为什么会这样吗?如果你需要知道,数据库的格式是这样的 ["1", "2", "3"]

错误:

Ignoring exception in command nominate:
Traceback (most recent call last):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "main.py", line 148, in nominate
    await update_db(nominated_persons, nominated_person)
  File "main.py", line 53, in update_db
    db[key] = [value]
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/replit/database/database.py", line 182, in __setitem__
    r = self.sess.post(self.db_url, data={key: j})
TypeError: unhashable type: 'list'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/bot.py", line 902, in invoke
    await ctx.command.invoke(ctx)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 864, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: unhashable type: 'list'

3 个答案:

答案 0 :(得分:0)

未经测试但请尝试以下操作

async def update_db(key, value):
  if key in db.keys():
      db[key].append(value)
  else:
      db[key] = [value]

通过比较我的代码和你的代码,你能明白为什么你会得到 TypeError 吗?

答案 1 :(得分:0)

好的,感谢您使用完整代码和回溯更新问题。

违规行是 db[key] = [value],它抛出一个 TypeError:unhashable type list, 这意味着您传递了一个列表类型作为 update_db 函数的关键参数。

这是不可能的,因为正如回溯明确指出的那样,您无法对列表类型进行哈希处理(这意味着您无法使用列表类型的键访问字典值)。

但痛苦的真正根源就在那条线之上:

if key in db.keys():
      key = db[key]
      key.append(value)
      db[key] = key

那是很多key,不是吗?这里的问题是你用变量名 key 指代不同的东西,结果有点混乱,所以我建议你用不同的变量来表示不同的东西:

async def update_db(key, value):
  if key in db.keys():
      old_value = db[key]
      old_value.append(value)
      db[key] = old_value
  else:
      db[key] = [value]

这样一来,数据库中实际更新的是 value 而不是 key,因此后者永远不会成为列表。

最后一个只是出于好奇。你为什么要定义一个函数来更新数据库,没有定义的方法来做到这一点吗?你用的是什么数据库?

答案 2 :(得分:0)

我找到了答案! 问题出在await update_db(nominated_persons, nominated_person) 就像那样,它不会更新数据库,因为 nominated_persons 未定义,所以我用 nominated_persons = db["nominated_persons"] 定义了它。但后来我会得到哈希错误,因为这是一个列表,我不能使用它,所以我只是做了 nominated_persons = "nominated_persons" 所以 nominated_persons 被定义为“nominated_persons”这个词。所以现在它起作用了

我觉得自己好傻

这是更新的代码:

@bot.command()
async def nominate(ctx, nominatedperson: discord.Member):
  print("command: nominate")
  nominated_person = nominatedperson.mention
  nominated_persons = "nominated_persons"
  await update_db(nominated_persons, nominated_person)
  await ctx.send("whatever")

(旁注:你可以在 update_db 命令中加入“nominated_persons”,你不必像我那样用变量来引用它。)