#python #discord.py #python-asyncio
Вопрос:
Я работаю над ботом discord для создания опросов, мой код здесь:
@bot.command(name="newpoll")
async def new_poll(ctx, question, *options):
if len(options) > 12:
await ctx.send("You can have a maximum of 12 choices in your poll")
else:
embed = discord.Embed(title = "Poll",
description = question,
colour = discord.Colour.red())
fields = [("Options", "n".join([f"{emotes[idx]} {option}" for idx, option in enumerate(options)]), False),
("Instructions", "Please react in order to vote!", False)]
for name, value, inline in fields:
embed.add_field(name = name, value = value, inline = inline)
embed = embed.add_field(name = "Total votes", value = 0, inline = False)
message = await ctx.send(embed = embed)
for emoji in emotes[:len(options)]:
await message.add_reaction(emoji)
message_win = await bot.get_channel(message.channel.id).fetch_message(message.id)
total_votes = sum(reaction.count for reaction in message_win.reactions) - len(options)
tv_embed = embed.set_field_at(2, name = "Total votes", value = total_votes, inline = False)
await message.edit(embed = tv_embed)
Общее количество голосов хранится в total_votes
переменной, которую я планирую отобразить, отредактировав встроенное сообщение, как в последних двух строках. Я хочу, чтобы это произошло в случае реакции. На этой ноте я попытался получить доступ к tv_embed
коду, аналогичному этому:
@bot.event
async def on_reaction_add(reaction, user):
print("planning to ember.set_field_at(...) here")
from_new_poll = await new_poll.tv_embed
from_new_polll = await new_poll.message
await from_new_polll.edit(embed = from_new_poll)
Но я получаю ошибку, подобную этой:
planning to ember.set_field_at(...) here
Ignoring exception in on_reaction_add
Traceback (most recent call last):
File "/home/vale/.virtualenvs/discord_env/lib/python3.9/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/home/vale/Documents/arcane/e_project-kindling/Discord-Bot/main.py", line 108, in on_reaction_add
from_new_poll = await new_poll.tv_embed
AttributeError: 'Command' object has no attribute 'tv_embed'
Не мог бы кто-нибудь, пожалуйста, любезно объяснить, что здесь происходит, заранее спасибо!
Ответ №1:
Простым методом может быть использование словаря или другой структуры данных, доступной, например, из любого места:
# after your bot instantiation (or at __init__)
bot = commands.Bot(...)
bot.polls = {}
# In same file commands:
@bot.command()
async def test(ctx):
print(bot.polls)
#In cogs:
self.bot.polls
ctx.bot.polls
Теперь в вашей команде опроса
msg = await ctx.send(...)
author_polls = bot.polls.setdefault(author, [])
author_polls.append(msg)
И, наконец, в вашем обработчике событий
msg = reaction.message
polls = bot.polls.get(msg.author)
if polls and msg in polls:
... # we know this reaction happened in a message that has a poll
В этом примере я просто сохранил исходное сообщение, но вы можете хранить там все, что вам нужно.
Учтите, что это небезопасно, так как перезапуск приведет к очистке данных и нарушит это. Вы должны использовать базу данных и хранить любые идентификаторы, которые вы хотите. Вы можете загрузить это и создать словарь при запуске, а затем просто обновлять его с каждым новым опросом.
Ответ №2:
Вы не можете получить доступ к переменным, определенным в другой функции, они видны только внутри этой функции, поэтому нигде больше. new_poll.tv_embed
по сути , это то же any_command.tv_embed
самое, что и то, что tv_embed
переменная не видна внешнему миру. Если вы об этом не знаете, я предлагаю вам scopes
немного разобраться.
Если вы хотите получить к нему доступ, вы должны сохранить его где-то за пределами функции (например, в качестве переменной в вашем Cog
файле или где-то еще в вашем .py
файле).
Я должен отметить, что если вы пытаетесь сделать что-то подобное, есть более серьезная проблема, и общий дизайн вашего кода просто не работает. Так почти никогда не бывает. В вашем случае вы можете получить доступ к исходному встраиванию из reaction
параметра и сразу же отредактировать его, не сохраняя его вообще нигде.
@bot.event
async def on_reaction_add(reaction, user):
# "reaction" has a "message" field that contains a reference to the message that the reaction was placed on
message = reaction.message
# A "Message" has a list of all embeds attached to this message, in your case I assume there's only one
tv_embed = message.embeds[0]
Обратите внимание , что вышеприведенное ^ приведет к сбою для сообщений, в которых их нет embeds
, это просто пример, чтобы дать вам представление здесь, а не полноценное решение. Вам понадобится кое if-statements
-что здесь и там, чтобы проверить, следует ли редактировать это встраивание или нет, поэтому проверьте, есть ли вообще встраивание для начала. Этого должно быть достаточно, чтобы заставить вас двигаться дальше, и эти чеки должны быть выписаны вами.
Для получения дополнительной информации см. Документы API для on_reaction_add, discord.Реакция и разногласия.Сообщение.
Комментарии:
1. Большое спасибо, сэр, за подробный ответ, изученный
scopes
иcog
, как вы предложили, и теперь, похоже, было бы лучше изучить и использоватьcog
вместо моего оригинального подхода.2. Если это решило вашу проблему, не забудьте принять ответ.