在**kwargs中使用对象(如Enum)作为键?
这是一个来自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 个回答
你真的想创建一个 MyEnum 的实例吗?
myenum = MyEnum()
func(myenum.X = 1)
我最开始的问题的答案确实是“没有”。不过,感谢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
(没有错误)
这个方法行不通,因为关键字参数的处理方式有问题。文档中提到:
[...] 接下来,对于每个关键字参数,标识符会用来确定对应的位置(如果标识符和第一个正式参数的名字相同,就用第一个位置,以此类推)[...]
所以必须有一种方法可以把字典中的键和正式参数的名字对应起来。这里有个例外:
关键字必须是字符串
当你试图传递一些不是字符串的东西时:
func(**{MyEnum.X: 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'