gpt4 book ai didi

python - python 3.9 上的 Typing.Optional 是否有更新,或者我做错了什么?

转载 作者:行者123 更新时间:2023-12-04 14:09:13 29 4
gpt4 key购买 nike

当我在 Discord.py 中为我的 bot 编写帮助命令时,此功能没有按预期工作。

def syntax(command):
cmd_and_aliases = '|'.join([str(command), *command.aliases])
params = []
for key, value in command.params.items():
if key not in ('self', 'ctx'):
params.append(f'[{key}]' if 'NoneType' in str(value) else f'<{key}>')
params = ' '.join(params)
return f'`{cmd_and_aliases} {params}`'

这个函数我想要的是,返回并打印名称和别名以调用不一致的命令,以及哪些部分是必需的,哪些部分不是正确运行该命令的。由于 Typing 中的 Optional[str] 可以翻译为 Union[str, None],我想得到的是它们可能是什么,如果它可以是 None,那么它将附加到方括号中的 params 列表 wrappend 中,或者在尖括号中。

`name|aliases <necessary part> [optional part]`

这是函数最初会返回的内容,但必要部分和可选部分都显示在尖括号中。

@command(name='slap', aliases=['hit'])
async def slap_member(self, ctx, member: Member, *, reason: Optional[str] = 'for no reason'):

例如,对于此命令,结果将如下所示。

slap|hit <Member> [reason]

但我最终得到的是:

slap|hit <Member> <reason>.

我是否做错了什么,或者是否有任何更新会破坏此功能?如果我做错了什么,请通过展示我可以做些什么来帮助我。

最佳答案

“为什么”

这种行为在 3.9 中确实发生了变化;我相信this commit specifically 是原因。看起来这些变化开始this提交,但我相信您的特定问题的表现是由于前者。

我对 typing 模块的管道不是很熟悉,但据我所知,Optional 的表示现在是特殊情况并且 按原样返回自身,即 typing.Optional[x] 而不是“扩展”为 typing.Union[x, NoneType]。然而,它们仍然具有相同的“类型”,但重要的是它们的“类型”已更改为 _UnionGenericAlias。 ,其 __repr__ 是:

def __repr__(self):
args = self.__args__
if len(args) == 2:
if args[0] is type(None):
return f'typing.Optional[{_type_repr(args[1])}]'
elif args[1] is type(None):
return f'typing.Optional[{_type_repr(args[0])}]'
return super().__repr__()

可能的解决方案

首先,我想指出您可以使用 command.clean_params而不是 command.params (据我所知,奇怪的是没有记录)。它的功能相同,除了它会自动排除 selfctx 因此您不必检查它。我将在下面的解决方案中使用它。

注意 clean_params 将参数返回为 inspect.Parameter对象,所以我们有一个额外的层要经过。

我想到了两种可能的解决方案。第一个非常接近您所拥有的,因为我们对 typing.Optional 进行简单的字符串检查:

for key, value in command.clean_params.items():
optional = str(value.annotation).startswith('typing.Optional')
params.append(f'[{key}]' if optional else f'<{key}>')

现在,在确定类型(在本例中为泛型)时,我个人不喜欢字符串检查,因此我会选择一些不同的东西。如 PEP 585 中所述,我们可以对泛型进行运行时自省(introspection),所以让我们利用它。

for key, value in command.clean_params.items():
anno = value.annotation
try:
optional = anno.__origin__ is Union and anno.__args__[1] is type(None)
except AttributeError:
optional = False
params.append(f'[{key}]' if optional else f'<{key}>')

这种方法的另一个好处是它可以在 Python 3.8 中工作(我认为 3.7 也是如此),而字符串检查版本显然只能在 3.9 中工作。您可以利用 sys.version_info 并进行多个字符串检查,但相比之下,这似乎太麻烦了。

关于python - python 3.9 上的 Typing.Optional 是否有更新,或者我做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65771191/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com