Multikey Multivalue Non Deterministic python dictionary

前端 未结 4 2000
清酒与你
清酒与你 2021-02-05 23:08

There is already a multi key dict in python and also a multivalued dict. I needed a python dictionary which is both:

example:

# probabilistically fetch a         


        
4条回答
  •  一个人的身影
    2021-02-05 23:12

    The OP wants as follows,

    d["red", "blue"] ={ 
        "baloon": haseither('red','green',0.8),
        "toy": hasonly("blue",0.15),
        "car": default(0.05)
    }  
    

    but this is data with embeded logic. It's very tedious to define a function for every value. What I suggest is to seprate the data and logic.

    Python has a data type for this, that's class. A callable instance of a class can be assigned to the dict and let the dict pass the keys and call the object to return the result.

    I've inherited and extended multiple_key_dict to support multi-key fetch and to pass keys to the object and call the object which has been stored in the dict.

    I assume data is recalculated per rule. This is Rule class, it has list of rules. A rule is a Python expressions and it has access to len function and keys list. So one can write a rule like len(keys) == 1 and 'blue' in keys.

    class Rule(object):
    
        def __init__(self, rule, data):
            self.rule = rule
            self.data = data
    

    This is Data class which has both set of data and rules.

    class Data(object):
        def __init__(self, rules):
            self.rules= rules
    
        def make_choice(self, data):
            data = tuple(self.make_list_of_values(data))
            return random.choice(data)
    
        def make_list_of_values(self, data):
            for val, weight in data:
                percent = int(weight * 100)
                for v in [val] * percent:
                    yield v
    
        def __call__(self, keys):
            for rule in self.rules:
                if eval(rule.rule,dict(keys=keys)):
                    return self.make_choice(rule.data)
    

    This is RuleDict, but non-callables can not be fetched.

    class RuleDict(multi_key_dict):
        def __init__(self, *args, **kwargs):
            multi_key_dict.__init__(self, *args, **kwargs)
    
        def __getitem__(self, keys):
            if isinstance(keys, str):
                keys = (keys, )
            keys_set = frozenset(keys)
            for key in self.keys():
                key = frozenset(key)
                if keys_set <= key:
                    return multi_key_dict.__getitem__(self,keys[0])(keys)
            raise KeyError(keys)
    

    usage example,

    d = RuleDict()
    rule1 = Rule('"red" in keys and "green" in keys',(('baloon',0.8), ('car',0.05), ('toy',0.15)))
    rule2 = Rule('len(keys) ==1 and "blue" in keys',(('baloon',0.25), ('car',0.35), ('toy',0.15)))
    data = Data((rule1, rule2))
    d['red','blue','green'] = data
    
    print(d['red','green'])  
    

    d['red','green'] calls the object, with keys, that was assigned and return the result.

    Another approach is, to make the dict callable. This one seems a sound approach, because data and logic are separate. By this, you pass the keys and the logic, a callable, to the dict and return the result. f.e.,

    def f(keys, data):
        pass # do the logic and return data
    
    d['red','blue','green'] = ('baloon', 'car', 'toy')
    

    Now call the dict

    d(('red','blue'),f)
    

    This is callable dict. If no callable is given, just returns the whole data.

    class callable_mkd(multi_key_dict):
        def __init__(self, *args, **kwargs):
            multi_key_dict.__init__(self, *args, **kwargs)
    
        def __call__(self, keys, process=None):
            keys_set = frozenset(keys)
            for key in self.keys():
                key = frozenset(key)
                if keys_set <= key:
                    if process:
                        return process(keys, self[keys[0]])
                    return self[keys[0]]
            raise KeyError(keys)
    

提交回复
热议问题