简体   繁体   中英

Python inheritance: Raising an error when non-overridden methods are called

I am writing a subclass of dict that maps from string keys to values of arbitrary types. If a key is a regex, it is stored and queried separately.

class RegexDict(dict):
    def __init__(self):
        super().__init__()  # non-regex keys in the parent class
        self.regex_dict = {}  # regex keys in the child class

    def __getitem__(self, key):
        try:
            return super().__getitem__(key)
        except KeyError:
            for x in self.regex_dict:
                if re.fullmatch(x, key):
                    return self.regex_dict[x]
        raise KeyError(key)

    def __setitem__(self, key, value):
        key, is_regex = key
        if is_regex:
            self.regex_dict[key] = value
        else:
            super().__setitem__(key, value)

Because this class will be used by other libraries (which is why I have to use inheritance), I want to make sure that an error is raised when non-overridden methods in the base class are called. How should I do this?

You should inherit from collections.abc.MutableMapping instead of dict.

It will fill in the gaps automatically, and also let you know which things you have to implement.

In addition to __getitem__ and __setitem__ , you'll also have to implement __delitem__ , __iter__ and __len_ . If you can't implement those reasonably, you can raise eg NotImplementedError from them (even though that will limit the use of your class a lot).

This will have the advantage that all dict methods which only need __getitem__ and __setitem__ (+ what you implement) internally will work out of the box.

Don't subclass. To convince third-party libs that your object is a dict , set __class__ attribute.

class RegexDict():
    __class__ = dict

    def __init__(self):
        self.non_regex_dict = {}
        self.regex_dict = {}

    def __getitem__(self, key):
        try:
            return self.non_regex_dict[key]
        except KeyError:
            for x in self.regex_dict:
                if re.fullmatch(x, key):
                    return self.regex_dict[x]
        raise KeyError(key)

    def __setitem__(self, key, value):
        key, is_regex = key
        if is_regex:
            self.regex_dict[key] = value
        else:
            self.non_regex_dict[key] = value

rd = RegexDict()
print(isinstance(rd, dict))
rd.clear()

output:

True
Traceback (most recent call last):
  File "libo.py", line 30, in <module>
    rd.clear()
AttributeError: 'RegexDict' object has no attribute 'clear'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM