简体   繁体   中英

I am a little bit confused by the super().__init__()

Here is my code:

class StrKeyDict(dict):
    def __init__(self):
        super().__init__()

    def __missing__(self, key):
        if isinstance(key, str):
            raise KeyError(key)
        return self[str(key)]

    def __contains__(self, key):
        return key in self.keys() or str(key) in self.keys()

    def get(self, key, default=None):
        try:
            return self[key]
        except KeyError:
            return default

if __name__ == "__main__":
    d = StrKeyDict([('2', 'two'), ('4', "four")])

I want to inherit the build-in dict, so I use super(). But when I use StrKeyDict([('2', 'two'), ('4', "four")]) to initialize it, error comes like this:

Traceback (most recent call last):
  File "/Users/nick/PyProjects/Fluent-Python/3-6.py", line 25, in <module>
    d = StrKeyDict([('2', 'two'), ('4', "four")])
TypeError: __init__() takes 1 positional argument but 2 were given

However, if I delete __init__() the whole class will work just fine. So my question is:

  1. Is super().__init__() a must in every class?
  2. If I want to keep super().__init__() , how would I modify?

By doing this class StrKeyDict(dict): you inherit dict, there is no need for init unless you want to initialize something when the class is created.

The error is raised because your call to create a StrKeyDict passed in the array and you did not allow for it in __init__ 's parameters. it should have been:

def __init__(self,  my_list):
   ...

etc

Is super().__init__() a must in every class?

No, you only need it when you want to run the inherited __init__ and do something extra, like only allowing certain parameters, or further mutating self afterwards.

In this case, where StrKeyDict.__init__() doesn't do anything extra, you should remove it and let StrKeyDict inherit dict.__init__() .

If I want to keep super().__init__() , how would I modify?

You would need StrKeyDict.__init__() to take arguments and pass them to super().__init__() .

If you want to be permissive/lazy, you can allow anything:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

Or if you want to be restrictive, match the signature of dict.__init__() :

def __init__(self, mapping_or_iterable, **kwargs):
    super().__init__(mapping_or_iterable, **kwargs)

PS I've let out some nuances here, but this should be enough to get you on your way.

  • Whenever you create a new instance of a class init method is called. It's like a constructer. Since your init method need not require any argument but you are passing a list, that's why you are getting this error. When you call the super method init method of inherited class is being called.

Here is rectified code:

class StrKeyDict(dict):
    def __init__(self,lst):
        super().__init__(lst)

    def __missing__(self, key):
        if isinstance(key, str):
            raise KeyError(key)
        return self[str(key)]

    def __contains__(self, key):
        return key in self.keys() or str(key) in self.keys()

    def get(self, key, default=None):
        try:
            return self[key]
        except KeyError:
            return default

if __name__ == "__main__":
    d = StrKeyDict([('2', 'two'), ('4', "four")])

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