I've got some imported packages with tricky structure and need to call some method that bases on lots of other methods with non-default parameters, which are not class attributes themself like pipeline in sklearn.
Minimal example of this module structure:
class Library_class:
def __init__(
self,
defined_class_options,
):
self.defined_class_options = defined_class_options
def method1( self , default_non_class_arg = 12 ):
assert self.defined_class_options==3
return default_non_class_arg
def method2( self, image ):
return image/ self.method1()
Default usage:
class_instance = Library_class( 3 )
class_instance.method2( 36 )
> 3.0
I need to set default_non_class_arg to 6 for example.
I've tried multiple approaches:
- Analogous to https://stackoverflow.com/a/35634198/7607734
class_instance.method2( 36 ,
method1__default_non_class_arg=3 )
TypeError: method2() got an unexpected keyword argument 'method1__default_non_class_arg'
It don't work probably because class definitely don't have set_params
- With setattr on redefined function
class_instance.__setattr__('method1',Library_class.new_method1)
class_instance.method2( 36 )
TypeError: new_method1() missing 1 required positional argument: 'self'
Both your snippets and question are quite messy, almost to the point of being unreadable.
Anyway, if you wantt to replace
method1with another function, saynew_method1in an specific instance, just do that. Your call to.__setattr__does that, but it is not needed at all, (and if it was, due to you not having the method to be replaced name at code writting time, and needed it as a parameter, it is more correct to call the built-insetattr, not the instance method: `setattr(class_instance, "method1", new_method1").Ordinarily, if you know, at code writting time you have to replace "method1" in an instance, the assigment operator will do it:
class_instance.method1 = new_method1What went wrong in your examle is that if you assign a method to an instance, instead of a class, you are bypassing the mechanism that Python uses to insert the
selfattribute into it - so your new_method1 needs a different signature. (and this is exactly what the error message "TypeError: new_method1() missing 1 required positional argument: 'self'" is saying):this will work.
new_method1could be written in a class body as well, and could be replaced just the same, but you would have to write it without theselfparameter the same, and then it would not work straight as a normal method.OR, you can, at assigment time, insert the
selfargument yourself - thefunctools.partialcall is a convenient way to do that:class MyClass: ... def method1(self, param1=36): ...
my_instance = MyClass()
from functools import partial MyClass.method1 = partial(MyClass.new_method1, my_instance)
Now, this should answer what you are asking, but it would not be honest of me to end the answer without saying this is not a good design. The best thing there is to pull your parameter from another place, it might be from an instance attribute, instead of replacing the method entirely just to change it.
Since for normal attributes, Python will read the class attribute if no instance attribute exists, it will happen naturally, and all you have to do is to set the new default value in your instance.