Generic dictionary

Steve D'Aprano steve+python at pearwood.info
Sun Nov 20 05:10:08 EST 2016


On Sun, 20 Nov 2016 08:27 pm, Thorsten Kampe wrote:

> I'd like to extend the dictionary class by creating a class that acts
> like a dictionary if the class is instantiated with a dictionary and
> acts like a "dictitem" ([(key1, value1), (key2, value2), ...]) if
> instantiated with a list (that is dictitem).

I'm not sure exactly what you are trying to accomplish here. You want a
single class that sometimes behaves like a dict, and sometimes behaves like
a list? Not just any list, but specifically a list of tuples of two items.

Frankly, that sounds... weird. Generally speaking, classes don't behave
differently according to how they are created. Consider:

float(123)  # int argument

float("123")  # str argument


The object you get back is the same, regardless of whether the class was
instantiated from an int or a str. That's a general principle of Object
Oriented Programming: an object's behaviour should depend on *what it is*,
not where it came from.


> The code (see extract at bottom) works well but it contains a lot of
> "if this is a dictionary then do as a dictionary already does"
> boilerplate code". How can I "inherit"(?)/"subclass"(?)/derive from
> dict so I don't have to write the code for the dictionary case?

class MyDict(dict):
    pass


inherits from dict. But that won't do what you want, since a dict doesn't
behave anything like a list of tuples. You'll have to over-ride
*everything*, filling your code with horrible stuff like this:


class MyDict(dict):
    def __init__(self, *args, **kwargs):
        super(MyDict, self).__init__(*args, **kwargs)
        # Decide whether to act like a list or a dict.
        if args and isinstance(args[0], dict):
            self._act_like_dict = True
        else:
            self._act_like_dict = False

    def __getitem__(self, key_or_index):
        if self._act_like_dict:
            # treat like a key
            super(MyDict, self).__getitem__(key_or_index)
         else:
            # treat like an index
            tmp = list(self.values())
            return tmp[key_or_index]

    def update(self, *args, **kwargs):
        if self._act_like_dict:
            super(MyDict, self).update(*args, **kwargs)
         else:
            raise TypeError('list doesn't support update')

    def sort(self, *args, **kwargs):
        if self._act_like_dict:
            raise TypeError('dict doesn't support sort')
         else:
            # somehow re-implement list sorting for something 
            # which is like a dict
            ...



Etc. It would be a monstrous pain in the posterior to write, and confusing
to use. Are you sure you want this? The whole concept of a class that
behaves differently depending on how you create it feels to me like that
movie "The Fly".

I think that a better strategy would be to reconsider. Why not just write
your code to accept *either* a dict, or a list of tuples? Then you don't
have to invent some monstrous hybrid class that is like the product of an
awful teleportation accident.






-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list