首页 > 解决方案 > 如何弃用 dict 键?

问题描述

问题

假设我在 python 中有一个函数,它返回一个带有一些对象的字典。

class MyObj:
    pass

def my_func():
    o = MyObj()
    return {'some string' : o, 'additional info': 'some other text'}

在某些时候,我注意到重命名密钥是有意义的,'some string'因为它具有误导性,并且不能很好地描述该密钥实际存储的内容。但是,如果我只是更改密钥,使用这段代码的人会非常恼火,因为我没有通过弃用期给他们时间来修改他们的代码。

当前尝试

因此,我考虑实现弃用警告的方式是在 dict 周围使用薄包装:

from warnings import warn

class MyDict(dict):
    def __getitem__(self, key):
        if key == 'some string':
             warn('Please use the new key: `some object` instead of `some string`')
        return super().__getitem__(key)

这样我可以用指向同一个对象的旧键和新键创建字典

class MyObj:
    pass

def my_func():
    o = MyObj()
    return MyDict({'some string' : o, 'some object' : o, 'additional info': 'some other text'})

问题:

标签: pythondictionary

解决方案


老实说,我认为您的解决方案没有什么特别错误或反模式,除了my_func必须复制每个已弃用的密钥及其替换的事实(见下文)。

您甚至可以稍微概括一下(以防您决定弃用其他键):

class MyDict(dict):
    old_keys_to_new_keys = {'some string': 'some object'}
    def __getitem__(self, key):
        if key in self.old_keys_to_new_keys:
            msg = 'Please use the new key: `{}` instead of `{}`'.format(self.old_keys_to_new_keys[key], key)
            warn(msg)
        return super().__getitem__(key)

class MyObj:
    pass

def my_func():
    o = MyObj()
    return MyDict({'some string' : o, 'some object': o, 'additional info': 'some other text'})

然后

>> my_func()['some string'])
UserWarning: Please use the new key: `some object` instead of `some string`

为了“弃用”更多键,您现在要做的就是 update old_keys_to_new_keys

然而,

请注意如何my_func复制每个已弃用的密钥及其替换项。这违反了 DRY 原则,并且在您确实需要弃用更多键时(并且您必须记住同时更新MyDict.old_keys_to_new_keys my_func)会使代码混乱。如果我可以引用雷蒙德·赫廷格的话:

一定会有更好的办法

这可以通过以下更改来解决__getitem__

def __getitem__(self, old_key):
    if old_key in self.old_keys_to_new_keys:
        new_key = self.old_keys_to_new_keys[old_key]
        msg = 'Please use the new key: `{}` instead of `{}`'.format(new_key, old_key)
        warn(msg)
        self[old_key] = self[new_key]  # be warned - this will cause infinite recursion if
                                       # old_key == new_key but that should not really happen
                                       # (unless you mess up old_keys_to_new_keys)
    return super().__getitem__(old_key)

然后my_func只能使用新密钥:

def my_func():
    o = MyObj()
    return MyDict({'some object': o, 'additional info': 'some other text'})

行为是相同的,任何使用已弃用密钥的代码都会收到警告(当然,访问新密钥也可以):

print(my_func()['some string'])
# UserWarning: Please use the new key: `some object` instead of `some string`
# <__main__.MyObj object at 0x000002FBFF4D73C8>
print(my_func()['some object'])
# <__main__.MyObj object at 0x000002C36FCA2F28>

推荐阅读