-2

In Python 3, I should be able to use super() in a class method as a substitute for the parent class:

class demodict(OrderedDict):

    def __setitem__(self, key, val):
        print(key)
        super().__setitem__(self, key, val)

The above behaves as expected when I instantiate a demodict() and add values to it. But if I use it as the data type for a ConfigParser object, something goes wrong:

>>> Config = configparser.ConfigParser(dict_type=demodict)
Traceback (most recent call last):
  File "<pyshell#15>", line 1, in <module>
    conf = configparser.ConfigParser(dict_type=demodict)
  File ".../anaconda/lib/python3.4/configparser.py", line 588, in __init__
    self._proxies[default_section] = SectionProxy(self, default_section)
  File "<pyshell#14>", line 5, in __setitem__
    super().__setitem__(self, key, val)
  File ".../anaconda/lib/python3.4/collections/__init__.py", line 67, in __setitem__
    if key not in self:
TypeError: unhashable type: 'demodict'

If I replace OrderedDict with plain dict as the parent class, the error gets even weirder:

Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    conf = configparser.ConfigParser(dict_type=demodict)
  File ".../anaconda/lib/python3.4/configparser.py", line 588, in __init__
    self._proxies[default_section] = SectionProxy(self, default_section)
  File "<pyshell#7>", line 6, in __setitem__
    super().__setitem__(self, key, val)
TypeError:  expected 2 arguments, got 3

If instead of super() I write OrderedDict or dict explicitly, I can use demodict as the dict_type with no problems. Can someone explain what is going on? (Since there is an easy work-around, I'm more curious about the cause than about the solution...)

alexis
  • 48,685
  • 16
  • 101
  • 161
  • 3
    `super().__setitem__` passes `self` as the first argument automatically. It works if you just do `super().__setitem__(key, val)`. – vaultah Nov 27 '17 at 19:06
  • Indeed! That solved the problem. Duh, but also, how strange. I should have read the docs on `super()` more carefully. Would you write it up as an answer with an explanation? – alexis Nov 27 '17 at 19:11
  • I can spare the points, but I'm curious why someone thinks this is a bad question. – alexis Nov 27 '17 at 19:15
  • @alexis You answered your own question with "*I should have read the [docs on super()](https://docs.python.org/3/library/functions.html#super) more carefully.*" RTFM questions seems to get downvoted these days... – wim Nov 27 '17 at 19:55
  • I was not the down-voter, so this is just a guess as to why (I think the question is fine and will be good for future users with possibly a change in title): the error message "expected 2 arguments, got 3" in the context of class methods is usually indicative of some error with `self`; perhaps the down-voter felt there was not enough research in the question. – SethMMorton Nov 27 '17 at 19:56

1 Answers1

1

Method attribute access on a super() proxy object, like ordinary method binding, just passes the object implicitly as the first positional argument.

Change this:

super().__setitem__(self, key, val)

To this:

super().__setitem__(key, val)

Note that OrderedDict doesn't use cooperative inheritance, i.e. it just calls dict.__setitem__ directly. Ideally, every object in the inheritance chain should be using super. Please proceed with caution if you plan to use OrderedDict with a multiple-inheritance structure.

wim
  • 338,267
  • 99
  • 616
  • 750
  • 2
    "Note that it is not the self that is passed, as vaultah's comment says, but a proxy object" - what are you talking about? – user2357112 Nov 27 '17 at 19:12
  • I mean `self` will be a `demodict` instance, and `super()` will be a `super` instance. – wim Nov 27 '17 at 19:17
  • 2
    `super()` will be a `super` instance, but the `super()` object isn't what'll be passed into the superclass `__setitem__` method as `self`. – user2357112 Nov 27 '17 at 19:18
  • I don't know how to explain it. The fact that the proxy object is the guy responsible for keeping track of the position in the mro, not the instance itself. If you have a better way, please edit it into my question directly. – wim Nov 27 '17 at 19:25