【问题标题】:How can I prevent getting an AttributeError after reloading a cog?重新加载 cog 后如何防止出现 AttributeError?
【发布时间】:2021-06-30 15:00:01
【问题描述】:

今天一个更不寻常的问题,但也许有人可以帮助我。

我正在开发一个与音乐有关的机器人。以下问题:

如果我在 cogreload 中更改内容,我总是会收到特定命令的 AttributeError: 'NoneType' object has no attribute 'XXXX' 错误。 有没有办法解决/防止这种情况?

例如,当机器人在语音通道中时会发生错误,然后我重新加载 cog

我向state查询每个与音乐有关的命令,可能与此有关吗?

state = self.get_state(ctx.guild)

get_state 的完整功能:

    def get_state(self, guild):
        """Gets the state for `guild`, creating it if it does not exist."""
        if guild.id in self.states:
            return self.states[guild.id]
        else:
            self.states[guild.id] = GuildState()
            return self.states[guild.id]

我尝试try/except AttributeError 解决它,但当然这并没有真正奏效/控制台仍然给了我输出。

这是一个示例代码:

    @commands.command()
    @commands.guild_only()
    @commands.check(audio_playing)
    @commands.check(in_voice_channel)
    @commands.check(is_audio_requester)
    async def loop(self, ctx):
        """Activates/Deactivates the loop for a song."""
        state = self.get_state(ctx.guild)
        status = state.now_playing.toggle_loop()
        if status is None:
            return await ctx.send(
                embed=discord.Embed(title=":no_entry:  Unable to toggle loop.", color=discord.Color.red()))
        else:
            return await ctx.send(embed=discord.Embed(
                title=f":repeat:  Loop: {'**Enabled**' if state.now_playing.loop else '**Disabled**'}.",
                color=self.bot.get_embed_color(ctx.guild)))

如果我在 cog 中进行更改,重新加载它,然后再次尝试运行 loop,我会收到以下 错误

In loop:
  File "C:\Users\Dominik\PycharmProjects\AlchiReWrite\venv\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "C:\Users\Dominik\PycharmProjects\AlchiReWrite\cogs\music.py", line 220, in loop
    status = state.now_playing.toggle_loop()
AttributeError: 'NoneType' object has no attribute 'toggle_loop'

(所有其他命令的错误相同)

请求,我们有 GuildState 类:

class GuildState:
    """Helper class managing per-guild state."""

    def __init__(self):
        self.volume = 1.0
        self.playlist = []
        self.message_queue = []
        self.skip_votes = set()
        self.now_playing = None
        self.control_message = None
        self.loop = False
        self.skipped = False

    def is_requester(self, user):
        return self.now_playing.requested_by == user

我将如何克服这个错误?

机器人加入命令play URL,然后我构建了以下内容:

if not state.now_playing:
    self._play_song(client, state, video)

_play_song主要定义如下:

    def _play_song(self, client, state, song):
        state.now_playing = song
    # Other things are not relevant

【问题讨论】:

  • @ŁukaszKwieciński 当然,我会编辑我的问题。
  • 能否也添加get_state方法?
  • @ŁukaszKwieciński 添加了方法get_state
  • 你能补充一下GuildState类是如何定义的吗?
  • @Benjin Sure,也将其添加到帖子中

标签: python discord discord.py attributeerror


【解决方案1】:

当您重新加载 cog 时,您的 cog 中的 states 字典将为空。使用state = self.get_state(ctx.guild),将创建一个新的GuildState 对象。从GuildState 类的__init__ 函数中,self.now_playing 设置为None

因此,status = state.now_playing.toggle_loop() 将抛出一个AttributeError,因为None 没有属性(在这种情况下,没有toggle_loop 属性)。

如果您想摆脱这些错误,您需要将self.now_playing 正确设置为具有所需属性的内容。

如果您想保持 states 字典原样,您可以在重新加载 cog 之前保存它并恢复它。下面的示例假设 cog 类名为 TestCog

@client.command()
async def reload(ctx):
    temp = client.get_cog('TestCog').states
    client.reload_extension('cog')
    client.get_cog('TestCog').states = temp

请注意,如果您更改 GuildState 的创建方式,这可能会破坏您的 cog,因为您正在恢复 states 的先前版本。

【讨论】:

  • 您能否仅凭您的知识/代码 sn-p 告诉我该错误我能做些什么?我看到 self.now_playing 设置为 None 但如果我将其设置为其他内容,则更改它会“跳过” AttributeError?
  • @Dominik 我假设您的代码将 state.now_playingNone 更改为它在某处获得了 toggle_next 属性,也许当机器人最初连接到语音通道时?你需要再做一次。如果您将其添加到您的问题中,我可能会提供帮助。
  • 我会在问题中添加一些内容。
猜你喜欢
  • 1970-01-01
  • 2022-01-16
  • 2013-03-13
  • 2021-05-12
  • 2015-12-05
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多