首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用dict值更新dict

用dict值更新dict
EN

Code Review用户
提问于 2016-01-21 00:42:51
回答 3查看 2.4K关注 0票数 2

这段代码工作正常,完全按照我的要求执行,但我觉得它很不雅观。例如,应该有一种使用get()和/或setdefault()的方法。欢迎所有意见和建议!

下面是一个函数,它构建了一个dict。迪克特的价值观也是一分为二。有些值是空的dicts {},有些是具有{key:value}对的数据集。

代码语言:javascript
复制
def my_function(my_string, my_key):

    d = {}

    for i in range(3):
        d['test' + str(i)] = {}

    d['test3'] = {'a_key': 'a_value'}

    # d = { 'test0': {}, 'test1': {}, 'test2': {}, 'test3': {'a_key': 'a_value'} }

    if my_string != '':
        d[my_key] = {my_string: None}

    else:
        # check if d[my_key] exists
        try:
            # d[my_key] exists and it is not empty, don't overwrite
            if d[my_key]:
                pass
            # d[my_key] exists, but it is empty, write NULL
            else:
                my_string = 'NULL'
                d[my_key] = {my_string: None}

        # d[my_key] did not exist, create it and write NULL
        except KeyError:
            my_string = 'NULL'
            d[my_key] = {my_string: None}

    return d


# my_string not blank, my_key is new
f = my_function('hello', 'test4')
print(f)

# my_string not blank, my_key exists
f = my_function('hello', 'test0')
print(f)

# my_string blank, my_key exists and its value is not empty
f = my_function('', 'test3')
print(f)

# my_string blank, my_key exists and its value is empty
f = my_function('', 'test0')
print(f)

# my_string blank, my_key is new
f = my_function('', 'test4')
print(f)

典型(和期望的)输出:

代码语言:javascript
复制
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'hello': None}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'hello': None}, 'test1': {}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'NULL': None}, 'test1': {}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'NULL': None}}
EN

回答 3

Code Review用户

回答已采纳

发布于 2016-01-21 09:59:22

测试

您提供了测试和预期的输出,这样您就可以检查行为,如果您可以运行测试而不必检查输出是否正确,这是件好事。只需要一点点重组就可以得到:

代码语言:javascript
复制
# my_string not blank, my_key is new
assert my_function('hello', 'test4') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'hello': None}}

# my_string not blank, my_key exists
assert my_function('hello', 'test0') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'hello': None}, 'test1': {}}

# my_string blank, my_key exists and its value is not empty
assert my_function('', 'test3') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}}

# my_string blank, my_key exists and its value is empty
assert my_function('', 'test0') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'NULL': None}, 'test1': {}}

# my_string blank, my_key is new
assert my_function('', 'test4') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'NULL': None}}

# New test from Sjoerd Job Postmus's comment
assert my_function('something not empty', 'test3') == {'test1': {}, 'test0': {}, 'test3': {'something not empty': None}, 'test2': {}}

改进

可以更简洁地重写if my_string != '':if my_string:

此外,还可以使用get以“安全”的方式检索元素。

因此,守则变成:

代码语言:javascript
复制
if my_string:
    d[my_key] = {my_string: None}
else:
    if not d.get(my_key):
        d[my_key] = {'NULL': None}
return d

此外,你的字典初始化可以通过一个词典的理解完成。然后,您的整个功能将成为:

代码语言:javascript
复制
def my_function(my_string, my_key):
    d = {'test' + str(i): {} for i in range(3)}
    d['test3'] = {'a_key': 'a_value'}

    if my_string:
        d[my_key] = {my_string: None}
    elif not d.get(my_key):
        d[my_key] = {'NULL': None}
    return d

就这么简单吗?不完全是?d.get(my_key)的检查实际上是将"test3“与其他值区分开来。只做一件显而易见的事情,而不是试图从dict中检索东西,可能会更容易:

代码语言:javascript
复制
def my_function(my_string, my_key):
    d = {'test' + str(i): {} for i in range(3)}
    d['test3'] = {'a_key': 'a_value'}
    if my_string:
        d[my_key] = {my_string: None}
    elif my_key != 'test3':
        d[my_key] = {'NULL': None}
    return d
票数 4
EN

Code Review用户

发布于 2016-01-21 09:55:09

我认为defaultdictS更适合你想要达到的目标。

您可以为缺少的值构建一个带有工厂的工厂,每次访问缺少的元素时,都会调用工厂来创建默认的元素。

基本上,您希望为缺失的值创建空字典:

代码语言:javascript
复制
from collections import defaultdict

my_dict = defaultdict(dict)
my_dict['test3']['a_key'] = value

print(my_dict) # defaultdict(<class 'dict'>, {'test3': {'a_key': 'value'}})

因此,您的实用程序函数只能检查第二个键的有效性,并插入到defaultdict中,而不管主键是否已经存在。

代码语言:javascript
复制
def my_function(my_string, my_key):
    d = defaultdict(dict)
    # Populate there with default values if need be
    ...
    # Write the new dictionary
    d[my_key][my_string if my_string != '' else 'NULL'] = None
    return d

如果不想覆盖已经定义的值,则可以使用setdefault,在键未定义时插入None (如果使用2个参数调用,则插入任何其他值),否则不会触及该值:

代码语言:javascript
复制
def my_function(my_string, my_key):
    d = defaultdict(dict)
    # Populate there with default values if need be
    ...
    # Write the new dictionary
    d[my_key].setdefault(my_string if my_string else 'NULL')
    return d

关于您的原始代码还有以下几点:

  • if my_string != ''是写得更好的if my_string。空字符串在布尔上下文中计算为False,其他每个字符串都是True
  • 您可以通过在try .. except之前定义new_dict = {'NULL': None}并在需要时分配d[my_key] = new_dict来消除try中涉及的冗余。
  • 您可以通过选择指示函数和变量(而不是它们是什么)的名称来改进整个命名。

但最糟糕的问题是,你的功能的行为似乎很奇怪。也就是说,您每次调用它时都会创建一个新的字典,因此其中没有任何内容,因此无需担心现有的值。我一点也不明白目的。也许您可以将字典作为参数传递并修改其内容。

类似于:

代码语言:javascript
复制
def set_default(storage, category, key):
    storage[category].setdefault(key if key else 'NULL')

与下列有关:

代码语言:javascript
复制
def create_default_storage():
    storage = defaultdict(dict)
    for i in range(3)
        storage['test'+str(i)]
    storage['test3']['a_key'] = 'value'
    return storage

你可以用它们就像:

代码语言:javascript
复制
storage1 = create_default_storage()
set_default(storage1, 'test4', 'hello')
set_default(storage1, 'test2', '')

storage2 = create_default_storage()
set_default(storage2, 'test3', 'a_key')
set_default(storage2, 'test0', '')

print(storage1)
print(storage2)

产出如下:

代码语言:javascript
复制
defaultdict(<class 'dict'>, {'test4': {'hello': None}, 'test3': {'a_key': 'value'}, 'test0': {'NULL': None}, 'test1': {}, 'test2': {}})
defaultdict(<class 'dict'>, {'test0': {'NULL': None}, 'test3': {'a_key': 'value'}, 'test2': {}, 'test1': {}})
票数 2
EN

Code Review用户

发布于 2016-01-21 09:55:14

这里确实有一些不雅的东西可以缩短。例如,使用循环构建d,但可以使用字典理解。它们就像列表理解(如果您曾经使用过),一个for循环折叠成一个用于构建字典的表达式(在本例中)。下面是它的样子:

代码语言:javascript
复制
d = {'test' + str(i): {} for i in range(3)}

这将基本上将每个键值对设置为'test' + str(i)键,将{}设置为range(3)中每个i的值。就像你原来的一样,但现在都成了一条线。

测试字符串是否为空的一种更优雅的方法是使用if my_string。这将返回空字符串的False,但对任何其他字符串返回True。您还可以通过在这里使用return来避免嵌套一定程度的缩进,因为如果my_string != ''

代码语言:javascript
复制
if my_string:
    d[my_key] = {my_string: None}
    return d

我将在您的pass块中再次使用return d来代替if d[my_key],因为它清楚地传达了再次发生的事情。

else块中,您可以只使用raise KeyError,而不是重复的代码,这样就可以使用that块。至于这个except块,不需要设置my_string,然后在赋值中使用它,只需使用字符串文字:

代码语言:javascript
复制
    except KeyError:
        d[my_key] = {'NULL': None}

另一个注意,您当前编写的测试if d[my_key]只有在my_key'test3'的情况下才是False,因为任何其他现有值都只会得到一个计算为False的空字典。还不完全清楚这是否是预期的行为,或者您只是不知道Python的真实性,但是d['test0']重新测试{}将被计算为False

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/117431

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档