在**kwargs中使用对象(如Enum)作为键?

2 投票
4 回答
2671 浏览
提问于 2025-04-30 05:24

这是一个来自Python新手的非常简单的问题:

我理解字典中的键可以是几乎任何不可变的数据类型。请问在函数或类的**kwargs字典中,能否使用不可变对象(比如枚举类的成员)作为键?我试过了,似乎答案是“不可以”:

from enum import Enum
class MyEnum(Enum):
    X= 'X'
    Y= 'Y'
def func(*args,**kwargs):
    pass
func(MyEnum.X = 1)

输出:

"SyntaxError: keyword can't be an expression"

不过,我可能漏掉了什么。

补充说明:我并不是想把键设置为MyEnum.X.value(在这种情况下是一个字符串);我想要的键是实际的Enum对象,比如MyEnum.X

暂无标签

4 个回答

-1

你真的想创建一个 MyEnum 的实例吗?

 myenum = MyEnum()
 func(myenum.X = 1)
0

我最开始的问题的答案确实是“没有”。不过,感谢mgilson、BartoszKP和其他人的建议,我想出的这个解决办法还不错,解决了我现在遇到的问题。我把它分享出来,希望对那些想做类似事情的人有帮助:

from enum import Enum
class MyEnum(Enum):
    X= 'X'
    Y= 'Y'

def func(*args,**kwargs):
    #replace kwargs with kwargsNew
    kwargsNew = {}
    for kwkey, kwvalue in kwargs.items():
        try: kwargsNew[MyEnum(kwkey)] = kwvalue
        except ValueError: kwargsNew[kwkey] = kwvalue
    doStuffWithKwargs(kwargsNew)

def doStuffWithKwargs(k):
    for K in k:
        print(K)

#Pass the name X or Y as the key; 
#all other keys not found in `MyEnum` are treated normally
func(X = 1, Y = 2, Z = 3)

输出结果:

Z
MyEnum.X
MyEnum.Y

(没有错误)

1

这个方法行不通,因为关键字参数的处理方式有问题。文档中提到

[...] 接下来,对于每个关键字参数,标识符会用来确定对应的位置(如果标识符和第一个正式参数的名字相同,就用第一个位置,以此类推)[...]

所以必须有一种方法可以把字典中的键和正式参数的名字对应起来。这里有个例外:

关键字必须是字符串

当你试图传递一些不是字符串的东西时:

func(**{MyEnum.X: 1})

这表明最简单的情况是:键必须是字符串。

一个可能的解决办法是把隐含的东西变得明确:创建一个包含你想传递的所有必要信息的类,把这些信息作为属性传递。这样代码会更容易阅读。

1

你正在做的是:

func(MyEnum.X = 1)

这里的问题在于 MyEnum.X = 1 -- 你的关键词(MyEnum.X)实际上是一个表达式(getattr(MyEnum, 'X')),而表达式不能用作函数调用中的关键词。实际上,只有 标识符 可以作为关键词。

要让你的调用正常工作,你需要像这样使用字典解包:

func(**{MyEnum.X.name: 1})

注意,要获取属性的名称,我需要使用 MyEnum.X.name 或者 MyEnum.X.value,这取决于你如何设置你的枚举 -- 在你的情况下,它们是一样的。

>>> from enum import Enum
>>> class Foo(Enum):
...   X = 'X'
... 
>>> Foo.X.value
'X'
>>> Foo.X.name
'X'

撰写回答