Home > Blockchain >  Handle dictionary based on one of the values
Handle dictionary based on one of the values

Time:01-20

I'm trying to find an elegant solution to this basic problem. I'm working on a webhook, I receive data in form of a json.

I have to handle the data based on one of the values.

import json

data = json.loads(raw_json)
data = {
  'type': 'A', # Type can be A, B or C
  'SomeAttribute' : 'SomeValue',
  'SomeOtherAttribute' : 'SomeOtherValue',
}

Based on the type I have to process the whole dictionary and perform some actions based one the type. Of course I could simply define some functions and make an infinite stack of ifs, but that doesn't look elegant.

if data['type'] == 'A':
    handle_type_A(data)
elif data['type'] == 'B':
    handle_type_B(data)
elif data['type'] == 'C':
    handle_type_C(data)
elif data['type'] == 'D':
    handle_type_D(data)
elif data['type'] == 'E':
    handle_type_E(data)

Strategy pattern seems the way ? I'm a beginner.

CodePudding user response:

I think it should be possible as following:

data = {
  'type': 'A', # Type can be A or B
  'SomeAttribute' : 'SomeValue',
  'SomeOtherAttribute' : 'SomeOtherValue',
}

def str2function(string:str):
   module = __import__('foo')
   func = getattr(module, 'bar')
   return func

func = str2function("handle_type_"   data["type"])
func(data)

Not absolutely shure about this method tho. Resource: https://stackoverflow.com/a/4605/20443541

or

data = {
  'type': 'A', # Type can be A or B
  'SomeAttribute' : 'SomeValue',
  'SomeOtherAttribute' : 'SomeOtherValue',
}

rule = {"A":hande_type_A, "B":handly_type_B}

rule[data["type"]](data)

You might adapt the code for other letters

CodePudding user response:

Welcome to Python! You haven't stated what "elegance" mean in this context, but my guess is that you don't like the if statements, mostly because you'd have to code, say, 25 branches for 25 types, in addition to your 25 different implementations of handle.

If you are new to classes in Python, and you are certain that every datum in your dataset is different only by its type, you may want to look at something like the following code:

import abc

class Datum(metaclass=abc.ABCMeta):

    def __init__(self, some_attr, some_other_attr):
        self._some_attr = some_attr
        self._some_other_attr = some_other_attr

    @abc.abstractmethod
    def tag():
        pass

    @abc.abstractmethod
    def handle(self):
        pass


class TypeA(Datum):
 
    @staticmethod
    def tag():
        return "A"

    def __init__(self, some_attr, some_other_attr):
        super().__init__(some_attr, some_other_attr)

    def handle(self):
        print("Type-A stuff.")


class TypeB(Datum):

    @staticmethod
    def tag():
        return "B"

    def __init__(self, some_attr, some_other_attr):
        super().__init__(some_attr, some_other_attr)

    def handle(self):
        print("Type-B stuff.")


class TypeC(Datum):

    @staticmethod
    def tag():
        return "C"

    def __init__(self, some_attr, some_other_attr):
        super().__init__(some_attr, some_other_attr)

    def handle(self):
        print("Type-C stuff.")

types = {datatype.tag() : datatype for datatype in [TypeA, TypeB, TypeC]}

Here, Datum is an abstract parent class, from which A, B, C, and possibly more derive or inherit. Every derived class will have its own implementation of handle, while still retaining its meaning as a datum, including its own other attributes. The final line defining types provides a way to select the correct type given a tag, as explained in the next code:

# your json file.
dataset = [{"Type" : "A", "SomeAttr" : "Thor", "SomeOtherAttr" : "Blue"},
           {"Type" : "B", "SomeAttr" : "Hulk", "SomeOtherAttr" : "Green"},
           {"Type" : "C", "SomeAttr" : "IronMan", "SomeOtherAttr" : "Red"}]

data = []
for entry in dataset:
    # `entry["Type"]` will be "A", "B", "C", ...
    # `types[entry["Type"]]` will be TypeA, TypeB, TypeC, ...
    # `types[entry["Type"]](entry["SomeAttr"], entry["SomeOtherAttr"])` will
    # construct Data object with appropriate handle function
    data.append(types[entry["Type"]](entry["SomeAttr"], entry["SomeOtherAttr"]))

# This will process every datum with appropriate handle function.
for d in data:
    d.handle()
  • Related