sho*_*app 40 python dictionary
我是Python的新手,有点惊讶我无法做到这一点.
dictionary = {
'a' : '123',
'b' : dictionary['a'] + '456'
}
Run Code Online (Sandbox Code Playgroud)
我想知道Pythonic在我的脚本中正确执行此操作的方法是什么,因为我觉得我不是唯一一个试图这样做的人.
编辑:足够的人想知道我在做什么,所以这里有更多我的用例的细节.让我们说我想保持字典对象来保存文件系统路径.路径相对于字典中的其他值.例如,这就是我的一本词典.
dictionary = {
'user': 'sholsapp',
'home': '/home/' + dictionary['user']
}
Run Code Online (Sandbox Code Playgroud)
重要的是,在任何时候我都可以改变dictionary['user']并让所有词典值反映出变化.再一次,这是我正在使用它的一个例子,所以我希望它能传达我的目标.
根据我自己的研究,我认为我需要实现一个类来完成这项工作.
jsb*_*eno 47
No fear of creating new classes - You can take advantage of Python's string formating capabilities and simply do:
class MyDict(dict):
def __getitem__(self, item):
return dict.__getitem__(self, item) % self
dictionary = MyDict({
'user' : 'gnucom',
'home' : '/home/%(user)s',
'bin' : '%(home)s/bin'
})
print dictionary["home"]
print dictionary["bin"]
Run Code Online (Sandbox Code Playgroud)
Ton*_*nen 14
我最近没有做对象:
dictionary = {
'user' : 'gnucom',
'home' : lambda:'/home/'+dictionary['user']
}
print dictionary['home']()
dictionary['user']='tony'
print dictionary['home']()
Run Code Online (Sandbox Code Playgroud)
>>> dictionary = {
... 'a':'123'
... }
>>> dictionary['b'] = dictionary['a'] + '456'
>>> dictionary
{'a': '123', 'b': '123456'}
Run Code Online (Sandbox Code Playgroud)
它工作正常但是当你尝试使用dictionary它时尚未定义(因为它必须首先评估该文字字典).
但要小心,因为这种分配给关键'b'的关键参考值'a' 在分配的时间并不会每次都做查找.如果这是你正在寻找的,那么它可能会有更多的工作.
这是一个有趣的问题.看起来格雷格有一个很好的解决方案.但那没什么好玩的;)
jsbueno是一个非常优雅的解决方案,但只适用于字符串(如您所要求的).
"通用"自引用字典的技巧是使用代理对象.它需要一些(低估的)代码行来完成,但用法是你想要的:
S = SurrogateDict(AdditionSurrogateDictEntry)
d = S.resolve({'user': 'gnucom',
'home': '/home/' + S['user'],
'config': [S['home'] + '/.emacs', S['home'] + '/.bashrc']})
Run Code Online (Sandbox Code Playgroud)
实现这一目标的代码并不是那么短暂.它分为三类:
import abc
class SurrogateDictEntry(object):
__metaclass__ = abc.ABCMeta
def __init__(self, key):
"""record the key on the real dictionary that this will resolve to a
value for
"""
self.key = key
def resolve(self, d):
""" return the actual value"""
if hasattr(self, 'op'):
# any operation done on self will store it's name in self.op.
# if this is set, resolve it by calling the appropriate method
# now that we can get self.value out of d
self.value = d[self.key]
return getattr(self, self.op + 'resolve__')()
else:
return d[self.key]
@staticmethod
def make_op(opname):
"""A convience class. This will be the form of all op hooks for subclasses
The actual logic for the op is in __op__resolve__ (e.g. __add__resolve__)
"""
def op(self, other):
self.stored_value = other
self.op = opname
return self
op.__name__ = opname
return op
Run Code Online (Sandbox Code Playgroud)
接下来是具体课程.很简单.
class AdditionSurrogateDictEntry(SurrogateDictEntry):
__add__ = SurrogateDictEntry.make_op('__add__')
__radd__ = SurrogateDictEntry.make_op('__radd__')
def __add__resolve__(self):
return self.value + self.stored_value
def __radd__resolve__(self):
return self.stored_value + self.value
Run Code Online (Sandbox Code Playgroud)
这是最后一堂课
class SurrogateDict(object):
def __init__(self, EntryClass):
self.EntryClass = EntryClass
def __getitem__(self, key):
"""record the key and return"""
return self.EntryClass(key)
@staticmethod
def resolve(d):
"""I eat generators resolve self references"""
stack = [d]
while stack:
cur = stack.pop()
# This just tries to set it to an appropriate iterable
it = xrange(len(cur)) if not hasattr(cur, 'keys') else cur.keys()
for key in it:
# sorry for being a duche. Just register your class with
# SurrogateDictEntry and you can pass whatever.
while isinstance(cur[key], SurrogateDictEntry):
cur[key] = cur[key].resolve(d)
# I'm just going to check for iter but you can add other
# checks here for items that we should loop over.
if hasattr(cur[key], '__iter__'):
stack.append(cur[key])
return d
Run Code Online (Sandbox Code Playgroud)
回应gnucoms关于为什么我按照我的方式命名类的问题.
单词代理通常与代替其他东西相关联,因此它似乎是合适的,因为这就是SurrogateDict类所做的:一个实例替换字典文字中的'self'引用.话虽如此,(除了有时直接愚蠢)命名可能是我编码最难的事情之一.如果你(或其他任何人)可以建议一个更好的名字,我会全力以赴.
我将提供一个简短的解释.Fromout S指的是SurrogateDict的一个实例,d是真正的字典.
引用S[key]触发S.__getitem__并 SurrogateDictEntry(key)放入d.
什么时候S[key] = SurrogateDictEntry(key)构建,它存储key.这将是key进入d该的此项对应的值SurrogateDictEntry是充当替代.
后S[key]返回,它要么进入d,或上面进行了一些操作(一个或多个).如果对它执行了操作,它将触发相对__op__方法,该方法简单地存储执行操作的值和操作的名称,然后返回自身.我们实际上无法解决操作,因为d尚未构建.
之后d构造,它被传递给S.resolve.此方法循环d 查找任何实例SurrogateDictEntry并使用resolve在实例上调用方法的结果替换它们.
该SurrogateDictEntry.resolve方法接收现在构造d为参数的方法,并且可以使用key它在构造时存储的值来获得它作为代理的值.如果在创建后op对其执行了操作,则将使用所执行操作的名称设置该属性.如果类有一个__op__方法,那么它有一个__op__resolve__方法,其中包含通常在方法中的实际逻辑__op__.所以现在我们有了逻辑(self.op_resolve)和所有必要的值(self.value,self.stored_value)来最终得到真正的价值d[key].所以我们返回第4步放在字典中的那个.
最后,该SurrogateDict.resolve方法返回d并解析所有引用.
那是一个粗略的草图.如果您还有其他问题,请随时提出.