Question: Python: magic methods that shouldn't be used

Question

Python: magic methods that shouldn't be used

Answers 3
Added at 2016-11-22 13:11
Tags
Question

I've created a class that is a tuple wrapper and tuples doesn't support item mutations. Should I leave __setitem__ and __delitem__ implementation or implement those methods like e.g. below (thus fall in kind of Refused Bequest code smell)? Which approach is more pythonic? Aren't custom exceptions better in such case?

def __setitem__(self, key, value):
    """
    :raise: Always.
    :raises: TypeError
    """
    self.data_set[key] = value  # Raise from tuple.

def __delitem__(self, key):
    """
    :raise: Always.
    :raises: TypeError
    """
    raise TypeError("Item deletion is unsupported")  # Custom exceptions thrown.
Answers
nr: #1 dodano: 2016-11-22 14:11

Implement one or the other or both if they make sense for your custom class.

If you implement __setitem__() you will be able to use yourobject[yourindex] = yourvalue syntax in your code (with the semantic that you choose to implement).

If you implement __delitem__() you will be able to use del yourobject[yourindex]

It makes no sense to explictly implement a method just to raise an Exception, Python will do it by default:

class Test(object):
    pass
test = Test()
test['foo'] = 'bar' # will call Test.__setitem__() which is not explicitly defined

will give TypeError: 'Test' object does not support item assignment

nr: #2 dodano: 2016-11-22 14:11

Although that is a matter of taste, I think you should not implement them at all. A class that has a __setitem__, __delitem__ implements the mutable collection protocol (either implicitly, or even explicitly by using collection abstract base classes). Your class just does not support this interface, that's it, and the user has neither reason nor right to assume it does

nr: #3 dodano: 2016-11-22 14:11

If your class is supposed to be a proper tuple subtype (according to Liskov substitution principle), then it should behave the same way as a tuple wrt/ to set/del - which as Guillaume mentions is the default behaviour if you just define neither __setitem__ nor __delitem__. I don't see how that would fall into the "Refused Bequest" category.

If your class uses a tuple as part of it's implementation but is NOT supposed to be a proper tuple subtype, then do whatever makes sense - but if you don't want to allow item assignment / deletion then again the simplest thing is to not implement them.

Source Show
◀ Wstecz