【问题标题】:derived value in a python mappython映射中的派生值
【发布时间】:2015-12-13 09:39:32
【问题描述】:

我不确定是否可以提出问题,但无论如何要问,假设我有一些字典:

 my_dict = {'a':0, 'b':1}

我想让一些键 'c' 等于(在这个简单的情况下)值 a+b,这样如果我要更新字典:

my_dict['a'] = 2

然后调用:

my_dict['c']

将返回 3 (a=2 + b=1)

我找不到任何简单的方法,也许是 lambda 函数,但这似乎不对。每当我想要 a 和 b 的总和时,这将很有用,我不必显式地将它们拉出并添加它们。

编辑:感谢您的快速响应,这将适用于一个类,如果我总是知道值 C 我想执行某些功能,但我希望能够动态定义该功能,让我们在 my_dict 中说我希望 'c' 是 a+b 但在其他一些 my_dict_2 我希望键 'b' 是 (key='a' * 52)/3 (或其他一些基本的数学运算。在下面的解决方案中,我会必须继续重写课程,我不想这样做。有什么想法吗?

【问题讨论】:

  • 我添加了更多“通用”解决方案,希望您会喜欢。
  • 请注意,Łukasz R.的最新解决方案非常灵活:您可以随时向现有实例添加新功能,并且与defaults中的键关联的lambda功能可以访问dict 中的任何值,包括defaults 中的普通值和特殊值,因此它可以变得任意复杂。

标签: python function dictionary


【解决方案1】:

你不能用一个普通的dict 来做到这一点,但你可以用一个类来做类似的事情:

class MyClass(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    @property
    def c(self):
        return self.a + self.b    

t = MyClass(2, 3)
print t.c
t.a = 10
print t.c
t.b = 5
print t.c

输出

5
13
15

【讨论】:

    【解决方案2】:

    通过实现一个简单的类来解决的典型问题。

    class MyClass(object):
        def __init__(self, a=None, b=None):
            self.a = a
            self.b = b
    
        @property
        def c(self):
            return self.a + self.b
    
    
    o = MyClass()
    o.a = 1
    o.b = 2
    assert o.c == 3
    o.a = 2
    assert o.c == 4
    

    如果您必须是 dict,您可以创建自定义类并覆盖 __getitem__ 魔术方法。

    class MyDict(dict):
        def __getitem__(self, key):
            if key == 'c':
                return self['a'] + self['b']
            return super(MyDict, self).__getitem__(key)
    
    
    my_dict = MyDict()
    my_dict['a'] = 1
    my_dict['b'] = 2
    assert my_dict['c'] == 3
    my_dict['b'] = 3
    assert my_dict['c'] == 4
    assert isinstance(my_dict, dict)
    

    如果你想要通用的解决方案,我会选择这样的:

    class DefaultDict(dict):
        defaults = {}
    
        def __getitem__(self, key):
            if key in self.defaults:
                return self.defaults[key](self)
            return super(DefaultDict, self).__getitem__(key)
    
        def __setitem__(self, key, value):
            if key in self.defaults:
                raise RuntimeError('Default key: %s' % key)
            super(DefaultDict, self).__setitem__(key, value)
    
    
    # alt. 1
    o1 = DefaultDict()
    o1.defaults = {'c': lambda d: d['a'] + d['b']}
    o1['a'] = 1
    o1['b'] = 2
    assert o1['c'] == 3
    
    
    # alt. 2
    class DefaultDict1(DefaultDict):
        defaults = {'c': lambda d: d['a'] + d['b']}
    
    
    o2 = DefaultDict1()
    o2['a'] = 1
    o2['b'] = 2
    assert o2['c'] == 3
    

    【讨论】:

    【解决方案3】:

    子类dict并覆盖__getitem__魔术函数:

    class SumDict(dict):
        SUM_KEY = 'c'
    
        def __getitem__(self, key):
            if key == self.SUM_KEY:
                return sum(self.values())
            return super(SumDict, self).__getitem__(key)
    
        def __setitem__(self, key, val):
            if key == self.SUM_KEY:
                raise KeyError('{} key is reserved'.format(key))
            super(SumDict, self).__setitem__(key, val)
    

    --

    >>> d = SumDict({'x': 1, 'y': 2, 'z': 3})
    >>> print(d['c'])
    6
    
    >>> d['c'] = 10
    KeyError: 'c key is reserved'
    

    【讨论】:

      猜你喜欢
      • 2021-12-23
      • 1970-01-01
      • 2021-08-04
      • 2019-03-03
      • 1970-01-01
      • 2021-07-07
      • 2013-03-26
      • 2021-08-07
      • 2010-11-23
      相关资源
      最近更新 更多