2015-02-10 45 views
2

我子类dict像这样在Python创建词典条目:使用点符号时,关键是一个迭代

class ObjectiveDict(dict): 

    def __getattr__(self, name): 
     if name in self: 
      return self[name] 
     else: 
      raise AttributeError("No such attribute: " + name) 

    def __setattr__(self, name, value): 
     """ 
     IMPORTANT NOTICE: when "name" is an iterator of an iterable, will not work, must use [] syntax 
     """ 
     self[name] = value 

    def __delattr__(self, name): 
     if name in self: 
      del self[name] 
     else: 
      raise AttributeError("No such attribute: " + name) 

现在,当我有类似:

objd = ObjectiveDict({'a':1, 'b':2, 'c':3}) 
objd.d = 4 

这种运作良好,输出:

{'a': 1, 'b': 2, 'c': 3, 'd': 4} 

但是,如果我有一列我想追加到objd,让我们用默认值表示,它将使用我用迭代器的名称来遍历列表中的一个关键,即:

keys = ['key1', 'key2', 'key3'] 
for k in keys: 
    objd.k = None 

它输出:

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'k': None} 

我知道我可以使用objd[k] = None或使用setattr方法克服此问题,但我想了解为什么当我使用点符号时,我的ObjectiveDict__setattr__方法将迭代器作为字符串?有没有办法修补我的代码,所以它符合点符号?

+0

因为'.'运算符的工作方式,属性名称作为字符串传递给'__setattr__'。在你的情况下,它会变成''''。 – 2015-02-10 10:54:54

+0

你需要在键中使用':k setattr(objd,k,None)';这是永远不会用点符号工作。正如@AshwiniChaudhary所说,'foo.bar ='baz''被翻译为'foo .__ setattr __('bar','baz')'。 – jonrsharpe 2015-02-10 11:01:04

回答

5

因为Python是连贯的。

在第一种情况下,您对objd.d = 4感到满意,翻译为objd['d'] = 4。但也有可能是:

d = 'e' 
objd.d = 4 

,你仍然会得到{'a': 1, 'b': 2, 'c': 3, 'd': 4}(希望{'a': 1, 'b': 2, 'c': 3, 'e': 4})。

所以,当你在第二种情况下写:

keys = ['key1', 'key2', 'key3'] 
for k in keys: 
    objd.k = None 

你只是重复objd.k = None,它被传递给objd['k'] = None,三次。

没有办法在点符号上使用的值的名称,您只能使用名称本身。

你可以把它的工作使用:

def __setattr__(self, name, value): 
    self[eval(name)] = value 

但我真的劝你不要那样做!在第一种情况下,你会得到:

d = 'e' 
objd.d = 4 
objd 

=>输出:{'a': 1, 'b': 2, 'c': 3, 'e': 4}