这段代码工作正常,完全按照我的要求执行,但我觉得它很不雅观。例如,应该有一种使用get()和/或setdefault()的方法。欢迎所有意见和建议!
下面是一个函数,它构建了一个dict。迪克特的价值观也是一分为二。有些值是空的dicts {},有些是具有{key:value}对的数据集。
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)典型(和期望的)输出:
{'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}}发布于 2016-01-21 09:59:22
您提供了测试和预期的输出,这样您就可以检查行为,如果您可以运行测试而不必检查输出是否正确,这是件好事。只需要一点点重组就可以得到:
# 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以“安全”的方式检索元素。
因此,守则变成:
if my_string:
d[my_key] = {my_string: None}
else:
if not d.get(my_key):
d[my_key] = {'NULL': None}
return d此外,你的字典初始化可以通过一个词典的理解完成。然后,您的整个功能将成为:
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中检索东西,可能会更容易:
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发布于 2016-01-21 09:55:09
我认为defaultdictS更适合你想要达到的目标。
您可以为缺少的值构建一个带有工厂的工厂,每次访问缺少的元素时,都会调用工厂来创建默认的元素。
基本上,您希望为缺失的值创建空字典:
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中,而不管主键是否已经存在。
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个参数调用,则插入任何其他值),否则不会触及该值:
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中涉及的冗余。但最糟糕的问题是,你的功能的行为似乎很奇怪。也就是说,您每次调用它时都会创建一个新的字典,因此其中没有任何内容,因此无需担心现有的值。我一点也不明白目的。也许您可以将字典作为参数传递并修改其内容。
类似于:
def set_default(storage, category, key):
storage[category].setdefault(key if key else 'NULL')与下列有关:
def create_default_storage():
storage = defaultdict(dict)
for i in range(3)
storage['test'+str(i)]
storage['test3']['a_key'] = 'value'
return storage你可以用它们就像:
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)产出如下:
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': {}})发布于 2016-01-21 09:55:14
这里确实有一些不雅的东西可以缩短。例如,使用循环构建d,但可以使用字典理解。它们就像列表理解(如果您曾经使用过),一个for循环折叠成一个用于构建字典的表达式(在本例中)。下面是它的样子:
d = {'test' + str(i): {} for i in range(3)}这将基本上将每个键值对设置为'test' + str(i)键,将{}设置为range(3)中每个i的值。就像你原来的一样,但现在都成了一条线。
测试字符串是否为空的一种更优雅的方法是使用if my_string。这将返回空字符串的False,但对任何其他字符串返回True。您还可以通过在这里使用return来避免嵌套一定程度的缩进,因为如果my_string != '':
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,然后在赋值中使用它,只需使用字符串文字:
except KeyError:
d[my_key] = {'NULL': None}另一个注意,您当前编写的测试if d[my_key]只有在my_key是'test3'的情况下才是False,因为任何其他现有值都只会得到一个计算为False的空字典。还不完全清楚这是否是预期的行为,或者您只是不知道Python的真实性,但是d['test0']重新测试{}将被计算为False。
https://codereview.stackexchange.com/questions/117431
复制相似问题