Wrapping a method from outside the class in Python with decorator
Question:
I would like to ask a question, how I can override/extend the existing external python class. I wanted to be able to call the same API, like parent class, but with some modifications.
Something like that:
[a]
b = 1
import configparser
# my wrapper class
class MyConfigParser(configparser.ConfigParser):
# override/wrap the parent class with all arguments (could be some optionals too) parent function has the same name, but it shouldn't be called
def getint(self, section, option):
# call the parent function, pass all args (maybe without mentioning them, ideally without copying them)
ret = parent.get(section, option)
# make modifications
print("my wrapper")
ret = ret + 1
# return modified value
return ret
config = MyConfigParser()
# call parent function
config.read('my-file.ini')
# call my wrapped-function
a = config.getint('a','b')
Just for an information, I’m unable to modify the parent class.
How to do that?
Answers:
I think you are confused about what a decorator is and what the word wrapping typically refers to. Neither of those apply here, if I understood your intent correctly.
Of course you can subclass some existing class that you may or may not have any control over and override its methods. And of course you can conveniently call the parent class’ methods from inside your own methods. In Python you typically use the built in super
proxy class for that. But none of this has anything to do with decoration or wrapping.
If you want to override a superclass’ method, you should take care to match its signature. Otherwise you would be violating type safety. If all you care about are a few specific arguments but not all of them, you can cheat a bit and collect the rest in the catch-all *args, **kwargs
parameters, but you should then pass them along to the superclass’ method call.
Also, you seemed to be calling the ConfigParser.get
method inside your overridden getint
method. But I am pretty sure that was a typo/mistake because you are clearly expecting the returned value that you assign to ret
to be an int
, whereas get
returns a str
. So you should be calling super().getint(...)
there.
Finally, if we are already at it, it is good form to properly annotate your functions with types. (see PEP 484 for details)
Here is what I think you need:
from configparser import ConfigParser
from typing import Any
class MyConfigParser(ConfigParser):
def getint(self, section: str, option: str, *args: Any, **kwargs: Any) -> int:
ret = super().getint(section, option, *args, **kwargs)
print("overridden `getint`")
ret += 1
return ret # type: ignore[no-any-return]
if __name__ == "__main__":
config = MyConfigParser()
config.read("my-file.ini")
print(config.getint("a", "b"))
The output with your example ini
-file:
overridden `getint`
2
There are a lot of questions and answers on this platform about super
and subclassing
as well as decorators
. I would suggest you search a bit and read up on those.
I would like to ask a question, how I can override/extend the existing external python class. I wanted to be able to call the same API, like parent class, but with some modifications.
Something like that:
[a]
b = 1
import configparser
# my wrapper class
class MyConfigParser(configparser.ConfigParser):
# override/wrap the parent class with all arguments (could be some optionals too) parent function has the same name, but it shouldn't be called
def getint(self, section, option):
# call the parent function, pass all args (maybe without mentioning them, ideally without copying them)
ret = parent.get(section, option)
# make modifications
print("my wrapper")
ret = ret + 1
# return modified value
return ret
config = MyConfigParser()
# call parent function
config.read('my-file.ini')
# call my wrapped-function
a = config.getint('a','b')
Just for an information, I’m unable to modify the parent class.
How to do that?
I think you are confused about what a decorator is and what the word wrapping typically refers to. Neither of those apply here, if I understood your intent correctly.
Of course you can subclass some existing class that you may or may not have any control over and override its methods. And of course you can conveniently call the parent class’ methods from inside your own methods. In Python you typically use the built in super
proxy class for that. But none of this has anything to do with decoration or wrapping.
If you want to override a superclass’ method, you should take care to match its signature. Otherwise you would be violating type safety. If all you care about are a few specific arguments but not all of them, you can cheat a bit and collect the rest in the catch-all *args, **kwargs
parameters, but you should then pass them along to the superclass’ method call.
Also, you seemed to be calling the ConfigParser.get
method inside your overridden getint
method. But I am pretty sure that was a typo/mistake because you are clearly expecting the returned value that you assign to ret
to be an int
, whereas get
returns a str
. So you should be calling super().getint(...)
there.
Finally, if we are already at it, it is good form to properly annotate your functions with types. (see PEP 484 for details)
Here is what I think you need:
from configparser import ConfigParser
from typing import Any
class MyConfigParser(ConfigParser):
def getint(self, section: str, option: str, *args: Any, **kwargs: Any) -> int:
ret = super().getint(section, option, *args, **kwargs)
print("overridden `getint`")
ret += 1
return ret # type: ignore[no-any-return]
if __name__ == "__main__":
config = MyConfigParser()
config.read("my-file.ini")
print(config.getint("a", "b"))
The output with your example ini
-file:
overridden `getint` 2
There are a lot of questions and answers on this platform about super
and subclassing
as well as decorators
. I would suggest you search a bit and read up on those.