python 相同的**kwargs,但一个引发“无法将字典更新序列元素#0转换为序列”

aurhwmvo  于 2023-04-19  发布在  Python
关注(0)|答案(1)|浏览(106)

我在dict继承方面遇到了一个非常奇怪的问题。我希望能够在dict对象的示例中传递自定义对象,因此我创建了一个自定义__new__方法来格式化这些对象,以便它们与dict.__new__方法兼容。
但我正面临着一个非常奇怪的问题.我已经阅读了大部分的主题谈论这个错误一stackoverflow,但没有一个是尽我的代码.这里是我的代码:

class TextureItem:
    def __init__(self, name: str = "stone") -> None:
        self.name = name

    def __repr__(self) -> str:
        return f'TextureItem({self.name})'

class GlobalPalette(dict[str, TextureItem]):
    def __new__(cls, *args, **kwargs):
        new_kwargs = {}
        print("args and kwargs:", args, kwargs, "\n")
        for arg in args:
            if isinstance(arg, list):
                for item in arg:
                    new_kwargs[item.name] = item
            elif isinstance(arg, dict):
                new_kwargs.update(arg)
            elif isinstance(arg, TextureItem):
                new_kwargs[arg.name] = arg
        if kwargs:
            new_kwargs.update(kwargs)
        print("new_kwargs:", new_kwargs, "\n")
        return super().__new__(cls, **new_kwargs)

a = GlobalPalette(stone=TextureItem(), v="OK")
print("a:", a, "\n\n")

b = GlobalPalette([TextureItem()], v="OK")
print("b:", b)

这是我在运行代码时得到的:

args and kwargs: () {'stone': TextureItem(stone), 'v': 'OK'}
new_kwargs: {'stone': TextureItem(stone), 'v': 'OK'} 

a: {'stone': TextureItem(stone), 'v': 'OK'} 

args and kwargs: ([TextureItem(stone)],) {'v': 'OK'}
new_kwargs: {'stone': TextureItem(stone), 'v': 'OK'} 

Traceback (most recent call last):
  File "/Users/n/ainbt/t.py", line 28, in <module>
    b = GlobalPalette([TextureItem()], v="OK")
TypeError: cannot convert dictionary update sequence element #0 to a sequence

最后的错误意味着我填充了一个像listtupleset这样的可迭代对象,它只包含“单个”对象。示例:[("a": 1), ("b": 2)]可以,但["a", "b"]会引发此错误。
这意味着它来自b = GlobalPalette([TextureItem()], v="OK")中的[TextureItem()]列表。但为什么它会检测到它,我自己的__new__应该在super().__new__之前执行。
我哪里做错了?谢谢

gblwokeq

gblwokeq1#

不能使用__new__设置字典项;这只能在__init__方法中完成。也就是说,考虑以下示例:

>>> dict.__new__(dict, v="OK")
{}

这正是你的代码正在做的事情。
我想你应该重写__init__,而不是__new__,像这样:

class TextureItem:
    def __init__(self, name: str = "stone") -> None:
        self.name = name

    def __repr__(self) -> str:
        return f'TextureItem({self.name})'

class GlobalPalette(dict[str, TextureItem]):
    def __new__(cls, *args, **kwargs):
        new_kwargs = {}
        print("args and kwargs:", args, kwargs, "\n")
        for arg in args:
            if isinstance(arg, list):
                for item in arg:
                    new_kwargs[item.name] = item
            elif isinstance(arg, dict):
                new_kwargs.update(arg)
            elif isinstance(arg, TextureItem):
                new_kwargs[arg.name] = arg
        if kwargs:
            new_kwargs.update(kwargs)
        print("new_kwargs:", new_kwargs, "\n")
        return super().__new__(cls, **new_kwargs)

a = GlobalPalette(stone=TextureItem(), v="OK")
print("a:", a, "\n\n")

b = GlobalPalette([TextureItem()], v="OK")
print("b:", b)

运行此命令将导致:

args and kwargs: () {'stone': TextureItem(stone), 'v': 'OK'} 

new_kwargs: {'stone': TextureItem(stone), 'v': 'OK'} 

a: {'stone': TextureItem(stone), 'v': 'OK'} 

args and kwargs: ([TextureItem(stone)],) {'v': 'OK'} 

new_kwargs: {'stone': TextureItem(stone), 'v': 'OK'} 

b: {'stone': TextureItem(stone), 'v': 'OK'}

相关问题