4

Is there a way to overwrite special functions for built in types in python? For example, I want to create a SpecialDict class that inherits from the built in dict. I want to allow users to define custom validation functions for both key and values in my special dictionary, like so:

def __init__(self, keyValidator = True, valueValidator = True):
    self.keyValidator = keyValidator
    self.valueValidator = valueValidator

Using this, I can intercept the addition of values in the update method, like so:

def update(self,key,value):
    assert (self.keyValidator(key))
    assert (self.valueValidator(key))
    self[key] = value

But this won't work if someone decides to just go ahead and use the [] as access. Or if someone creates the object using a dictionary literal.

mySpecialDict = SpecialDict
mySpecialDict['hello'] = 54
1
  • Pretty much every syntax you see standard objects support can be implemented by hand in Python. There's extensive documentation on the matter in their website. Commented May 17, 2012 at 22:48

4 Answers 4

4

Someone can't create an instance of your SpecialDict as a dictionary literal, because a dictionary literal is just that; a normal dictionary.

As far as setting items with square bracket notation, as in mySpecialDict['hello'] = 54, that just corresponds to mySpecialDict.__setitem__('hello', 54). Likewise retrieving an item with the square bracket notation corresponds to an invocation of the __getitem__ method. This is true no matter what class mySpecialDict is; whether it's an ordinary dictionary, a class that subclasses the builtin dict, or some entirely unrelated class. So you can just implement those methods to change what they do (using super(SpecialDict, self).__setitem__(key, value) or dict.__setitem__(self, key, value) to refer to the normal implementation, when you need to).

One problem you will run into is that some (all?) of the builtin implementation of other dict methods will not respect your overridden __setitem__ or __getitem__. So you won't be able to inherit them; you'll have to override all of them and either completely re-implement them in terms of your versions of the basic operations, or at least run your validations "around" the superclass calls.

A much less painful approach might actually be to not subclass the builtin dict, and instead implement a custom "dict-like" object that wraps an ordinary dictionary, using the collections.Mapping or collections.MutableMapping base classes to get the dictionary interface. Using this approach you'll only need to implement about 6 basic methods yourself (which you'd do by plugging in your validation logic around calls to the wrapped dictionary), and get sensible definitions of other methods based on them. See http://docs.python.org/library/collections.html#collections-abstract-base-classes

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for the in depth answer. It answered my question and diagnosed my underlying problem.
2

You can override the special method __getitem__ to implement your own behavior of the [] operator. See this for more information.

1 Comment

It'd be best to add the __setitem__ and __missing__ methods in your answer.
0

You can override __setitem__(self, key, val) method, and use super(SpecialDict, self).__setitem__ to access parent object's (i.e. dicts) method:

class SpecialDict(dict):
    def __init__(self, keyValidator = lambda x:True, valueValidator = lambda x:True):
        self.keyValidator = keyValidator
        self.valueValidator = valueValidator
    def __setitem__(self, key, val):
        assert (self.keyValidator(key))
        assert (self.valueValidator(val))
        super(SpecialDict, self).__setitem__(key, val)

Please also note using lambdas as default values: using simply True or False will lead to the error since they are not callable.

Comments

-1

Thunder!

I'm in a mobile device so won't be able to give a complete answer but look up __getitem__ and __setitem__

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.