Is there an “infinite dictionary” in Python?

2019-09-17 12:05发布

问题:

Is there something like an "infinite dictionary" in Python?

More precisely, is there something where - i can put in values like in a dictionary, - but maybe also a function which tells me how to map a key to a value, - and maybe also something that maps a key to a (finite) set of keys and then gives the corresponding value? Formulated in another way, what I want to have is the following "thing": I initialize it in a way (give values, functions, whatever) and then it just gives me for each key a value (on request).

回答1:

What you need is called a "function".

Now, on a less sarcastic note: I don't know exactly what you are trying to achieve, but here's an example:

You want a piece of code that returns the nth element in an arithmetic progression. You can do it this way with functions:

def progression(first_element, ratio):
    def nth_element(n):
        return n*ratio + first_element
    return nth_element

my_progression = progression(2, 32)
print my_progression(17) # prints 546

This can be extended if, for example, you need a function that retains state.

Hope this helps



回答2:

You will want to create a class with the special method __getitem__(self,key) that returns the appropriate value for that key.



回答3:

If you want normal behaviour for existing keys, and special behavior for non-existing keys, there's the __missing__ method that's called for missing keys.

class funny_dict(dict):
    def __missing__(self, key):
        return "funny" * key

d = funny_dict()
d[1] = "asdf"
d[3] = 3.14
for i in range(5):
    print(i, d[i])

print(d)

Output:

0 
1 asdf
2 funnyfunny
3 3.14
4 funnyfunnyfunnyfunny
{1: 'asdf', 3: 3.14}


回答4:

An easy way to do this would be to use a function object for both use cases. If you want to use a key-value function, you just just use it directly as a reference. To adapt an ordinary dictionary to this interface, you can wrap it in a lambda block. Like so:

# Use function as dictionary
def dict_func(key):
    return key * key
dictionary = dict_func
print dictionary(2) # prints 4

# Use normal dictionary with the same interface
normal_dict = {1: 1, 2: 4, 3: 9}
dictionary = lambda(key): normal_dict[key]
print dictionary(2) # also prints 4

# Lambda functions store references to the variables they use,
# so this works too:
def fn_dict(normal_dict):
    return lambda(key): normal_dict[key]
dictionary = fn_dict({1: 1, 2: 4, 3: 9})
print dictionary(3) # prints 9


回答5:

I think you want something like this, where you dict act like a normal dictionary but for special keys you want to change the behavior e.g.

class InfiniteDict(dict):
    def __init__(self, *args, **kwargs):
        self.key_funcs = kwargs.pop('key_funcs', [])
        super(InfiniteDict, self).__init__(*args, **kwargs)

    def __getitem__(self, key):
        try:
            return super(InfiniteDict, self).__getitem__(key)
        except KeyError:
            return self._get_value_from_functions(key)

    def _get_value_from_functions(self, key):
        """
        go thru list of user defined functions and return first match
        """
        for key_func in self.key_funcs:
            try:
                return key_func(key)
            except KeyError:
                pass

        raise KeyError(key)

def double_even_int(key):
    try:
        if int(key)%2 == 0:
            return int(key)*2
        else:
            raise KeyError(key)
    except ValueError:
        raise KeyError(key)

def tripple_odd_int(key):
    try:
        if int(key)%2 == 1:
            return int(key)*3
        else:
            raise KeyError(key)
    except ValueError:
        raise KeyError(key)

inf = InfiniteDict(key_funcs=[double_even_int, tripple_odd_int])
inf['a'] = 'A'

print inf['a'], inf[1], inf['2']

output:

A 3 4