如何防止在重新加载齿轮后出现 AttributeError?

How can I prevent getting an AttributeError after reloading a cog?

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

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

如果我在 cog 中更改内容,然后在 reload 中更改内容,我总是会收到特定命令的 AttributeError: 'NoneType' object has no attribute 'XXXX' 错误。 有办法fix/prevent吗?

例如,当机器人在语音通道中时发生错误,然后我重新加载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 解决它,但当然那不是真的 work/the 控制台仍然给了我输出。

示例代码如下:

    @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:

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

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

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

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

如果你想保持 states 字典不变,你可以在重新加载你的 cog 之前保存它并恢复它。下面的例子假设 cog class 被命名为 TestCog.

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

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