使用__setattr __重写库类别类别的整个方法:缺少1所需的位置参数:' self'

发布于 2025-01-30 13:21:46 字数 1526 浏览 5 评论 0原文

我有一些带有棘手结构的导入软件包 并需要调用一些基于许多其他方法的方法 使用非默认参数,这不是类,将它们像sklearn中的管道一样归因于他们。

此模块结构的最小示例:

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()

默认用法:

    class_instance = Library_class( 3 )
    class_instance.method2( 36 )
> 3.0

例如,我需要将DEFAULT_NON_CLASS_ARG设置为6。

我已经尝试了多种方法:

  1. 类似于 https://stackoverflow.com/a/a/35634198/76077734
    class_instance.method2( 36 ,
                 method1__default_non_class_arg=3  )

typeerror:method2()有一个意外的关键字参数'method1__default_non_class_arg'

它可能无法正常工作,因为重新定义函数上的class肯定没有

  1. setAttr
    class_instance.__setattr__('method1',Library_class.new_method1)
    class_instance.method2( 36 )
set_params

typeerror:new_method1()缺少1所需的位置参数:'self'

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:

  1. 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

  1. 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'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

秋日私语 2025-02-06 13:21:46

您的片段和问题都非常凌乱,几乎是不可读的地步。

无论如何,如果您希望将method1替换为另一个功能,则在特定实例中say new_method1,请执行此操作。您呼叫.__ setAttr __这样做,但根本不需要(如果是,由于您没有在代码写入时间替换名称的方法,并且需要它作为一个参数,调用内置setAttr,而不是实例方法:`setAttr(class_instance,“ method1”,new_method1')。

通常,如果您知道,请在代码签名时您必须在一个实例中替换“方法1”,评估操作员将执行此操作:

class_instance.method1 = new_method1

审查中的问题是,如果您将方法分配给实例,而不是类,您正在绕过Python用来将self属性插入其中的机制 - 因此您的new_method1需要其他签名(这正是错误消息“ typeerror:new_method1()缺少1个缺失1位置论点:“自我”在说):

class  MyClass:
    ...
    def method1(self, param1=36):
         ...
    ...

def new_method1(param1=6):   # <-- written outside of any class body, sans self
    ...

my_instance = MyClass()
my_instance.method1 = new_method1 

这将起作用。
new_method1也可以写在班级主体中,并且可以替换相同,但是您必须在没有self参数的情况下编写它,然后不会作为正常方法直接起作用。

或者,您可以在评估时插入self参数自己 -functools.partial调用是一种方便的方法:

类myclass: class myclass:
...
def方法1(self,param1 = 36):
...

def new_method1(self, param1=6):  
     ...
...

my_instance = myClass()

来自functools导入部分
myClass.method1 = partial(myClass.new_method1,my_instance)


,这应该回答您要问的内容,但是在不说这不是一个好设计的情况下结束答案并不诚实。最好的方法是从另一个地方提取您的参数,它可能是从实例属性中提取的,而不是完全替换该方法只是为了更改它。

由于对于普通属性,如果不存在实例属性,Python将读取类属性,它将自然发生,而您要做的就是在您的实例中设置新的默认值。

class  MyClass:
    default_param_1 = 36  # Class attribute. Valid for every instance unless overriden
    ...
    def method1(self, param1=None):
         if param1 is None:
               param1 = self.default_param_1  #Automatically fetched from the class if not set on the instance
         ...
    ...


my_instance = MyClass()
my_instance.default_param_1 = 6
...

Both your snippets and question are quite messy, almost to the point of being unreadable.

Anyway, if you wantt to replace method1 with another function, say new_method1 in 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-in setattr, 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_method1

What 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 self attribute 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):

class  MyClass:
    ...
    def method1(self, param1=36):
         ...
    ...

def new_method1(param1=6):   # <-- written outside of any class body, sans self
    ...

my_instance = MyClass()
my_instance.method1 = new_method1 

this will work.
new_method1 could be written in a class body as well, and could be replaced just the same, but you would have to write it without the self parameter the same, and then it would not work straight as a normal method.

OR, you can, at assigment time, insert the self argument yourself - the functools.partial call is a convenient way to do that:

class MyClass:
...
def method1(self, param1=36):
...

def new_method1(self, param1=6):  
     ...
...

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.

class  MyClass:
    default_param_1 = 36  # Class attribute. Valid for every instance unless overriden
    ...
    def method1(self, param1=None):
         if param1 is None:
               param1 = self.default_param_1  #Automatically fetched from the class if not set on the instance
         ...
    ...


my_instance = MyClass()
my_instance.default_param_1 = 6
...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文