让我感到惊讶的是,这种行为也会延续到常数:
use strict;
use warnings;
use Data::Dump 'dump';
use constant data => {
'foo' => {
'bar' => 'baz',
},
'a' => {
'b' => 'c',
}
};
dump data; # Pre-modified
print "No data for 'soda->cola->pop'\n" unless exists data->{soda}{cola}{pop};
dump data; # data->{soda}{cola} now sprung to life
Run Code Online (Sandbox Code Playgroud)
产量
Run Code Online (Sandbox Code Playgroud){ a => { b => "c" }, foo => { bar => "baz" } } No data for 'soda->cola->pop' { a => { …
代码示例如下.调用追加哈希值会正确返回,但哈希本身的行为并不像我期望的那样.
ruby-1.9.2-p290 :037 > r = {}
=> {}
ruby-1.9.2-p290 :038 > r.default = []
=> []
ruby-1.9.2-p290 :039 > r["c"] << 1
=> [1]
ruby-1.9.2-p290 :040 > r["c"]
=> [1]
ruby-1.9.2-p290 :041 > r
=> {}
ruby-1.9.2-p290 :042 > r.empty?
=> true
Run Code Online (Sandbox Code Playgroud) 自动生成只与"derefencing"未定义的结构有关,因为在JavaScript中,如果指定索引或不存在的属性,它是否会动态创建它?但这不是自动生成,因为你必须声明底层结构首先是一个对象或一个数组?
TL; DR
在为子键分配值时,如何在Python dict中使超级密钥自动生成,而不检查子键时是否自动生成它们?
背景: 通常在Python中,在嵌套字典中设置值需要在分配给子键之前手动确保存在更高级别的键.那是,
my_dict[1][2] = 3
Run Code Online (Sandbox Code Playgroud)
如果没有先做类似的事情,将不会按预期可靠地工作
if 1 not in my_dict:
my_dict[1] = {}
Run Code Online (Sandbox Code Playgroud)
现在,可以通过创建my_dict覆盖类的实例来设置一种自动生成,__missing__例如在/sf/answers/1388080011/中所示.
问题:但是,如果您在这样的嵌套字典中检查是否存在子键,那么该解决方案会自动对高级别密钥进行自动生成.这导致以下不幸:
>>> vd = Vividict()
>>> 1 in vd
False
>>> 2 in vd[1]
False
>>> 1 in vd
True
Run Code Online (Sandbox Code Playgroud)
我怎样才能避免这种误导性的结果呢?顺便说一句,在Perl中,我可以通过这样做获得所需的行为
no autovivification qw/exists/;
Run Code Online (Sandbox Code Playgroud)
基本上我想在可能的情况下在Python中复制该行为.
我想这样做:
$matched_tags[$tag]++
作为跟踪在循环期间找到给定 $tag 的次数的一种简单方法。
这似乎是在第一次遇到任何新 $tag 时抛出 NOTICE,因为索引未定义。PHP 友好地自动激活它,将其设置为 0 并对其进行后增量,但无论如何都会抛出 NOTICE。
现在我喜欢将通知作为最佳实践进行开发,所以我不想压制它们。但对我来说,我所做的并不值得关注。
我真的必须:
if ( ! isset ( $matched_tags[$tag] ) ) $matched_tags[$tag] = 0;
$matched_tags[$tag]++;
Run Code Online (Sandbox Code Playgroud)
哦,那太痛苦了。请告诉我有一种更优雅的方式,否则我发誓我会切换到 Perl,所以请帮助我。
我有下一个程序:
use warnings;
use strict;
BEGIN {
print \&mysub;
}
sub mysub {};
print \&mysub;
Run Code Online (Sandbox Code Playgroud)
它的输出:
CODE(0x118e890)CODE(0x118e890)
Run Code Online (Sandbox Code Playgroud)
该BEGIN块在编译时处理.那时sub mysub编译器还没有看到定义.但是程序仍会打印正确的子程序地址,它在定义时会有.
为什么我这里没有错误?这是某种自动化吗?
我正在对大约10000行数进行分析,有些行给出了错误:"在数字上下文中使用Any的未初始化值".我试图捕获此错误,以查看哪些行导致问题.但是,X :: TypeCheck和其他X ::*类似乎没有有效地捕获Nil或Any的自动生成.例如:
try { say Any + 1; CATCH { default { say "oh-no"; } }; }
Run Code Online (Sandbox Code Playgroud)
在打印出警告信息后仍然给我回答"1"并且没有说出我想要的"哦 - 不".
捕获这些非致命自动更新错误的正确方法是什么?顺便说一下,是否有核动力的perl6调试器?
非常感谢你 !!!
lisprog
我想就扩大了例如自动激活 从前面的回答给nosklo允许通过元组字典的访问.
nosklo的解决方案如下所示:
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
Run Code Online (Sandbox Code Playgroud)
测试:
a = AutoVivification()
a[1][2][3] = 4
a[1][3][3] = 5
a[1][2]['test'] = 6
print a
Run Code Online (Sandbox Code Playgroud)
输出:
{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
Run Code Online (Sandbox Code Playgroud)
我有一个案例,我想设置一个节点给定一些任意的下标元组.如果我不知道元组将有多少层,我该如何设计一种设置适当节点的方法?
我想也许我可以使用如下语法:
mytuple = (1,2,3)
a[mytuple] = 4
Run Code Online (Sandbox Code Playgroud)
但是我无法想出一个有效的实施方案.
我有一个基于@ JCash答案的完整工作示例:
class NestedDict(dict):
"""
Nested dictionary of arbitrary depth with autovivification.
Allows data access via …Run Code Online (Sandbox Code Playgroud) 我正在使用自动激活将数据存储在多处理设置中。但是,我不知道如何将它合并到多处理管理器功能中。
我的自动激活代码来自Python 中的多级 'collection.defaultdict'并且在没有多处理发生时工作正常。
class vividict(dict):
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
Run Code Online (Sandbox Code Playgroud)
我的 multiproc 代码是相对简单的:
if __name__ == "__main__":
man = Manager()
ngramDict = man.dict()
print(ngramDict) # {}
s_queue = Queue()
aProces = Process(target=insert_ngram, args=(s_queue,ngramDict,))
aProces.start()
aProces.join()
print(ngramDict) # {}
write_to_file()
Run Code Online (Sandbox Code Playgroud)
在 insert_ngram 中读取、写入和更新字典:
def insert_ngram(sanitize_queue, ngramDict):
ngramDict = Vividict() # obviously this overwrites the manager
try:
for w in iter(s_queue.get, None):
if ngramDict[w[0]][w[1]][w[2]][w[3]][w[4]]:
ngramDict[w[0]][w[1]][w[2]][w[3]][w[4]]+=int(w[5])
else:
ngramDict[w[0]][w[1]][w[2]][w[3]][w[4]]=int(w[5])
print(ngramDict) …Run Code Online (Sandbox Code Playgroud) 哈希初始值设定项:
# this
animals = Hash.new { [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {}
# is not the same as this
animals = Hash.new { |_animals, type| _animals[type] = [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]}
Run Code Online (Sandbox Code Playgroud)
我看到有人在另一个问题上发布这些内容,但我不明白为什么动物在第一种情况下显得空白.如果我输入
animals[:dogs]
Run Code Online (Sandbox Code Playgroud)
我得到了合适的数组.
autovivification ×10
python ×3
dictionary ×2
hash ×2
perl ×2
ruby ×2
constants ×1
exception ×1
javascript ×1
notice ×1
perl6 ×1
php ×1
slice ×1
subroutine ×1