【问题标题】:wrap a function as a method in a subclass of a class in python将函数包装为python中类的子类中的方法
【发布时间】:2021-06-20 06:54:18
【问题描述】:

这是(简化的)案例:

我有一个包含子类的类:

>>> inst = Foo()
>>> inst.sub.bar()

它从子类的 bar() 方法返回了一些很棒的东西。
这是这样写的:

class Sub() :
    def __init__(inst) :
        self.inst = inst

    def bar(self) :
        '''does something magnificent  with the Foo instance (self.inst)'''
        return smtg

class Foo() :
    def __init__(self, *args, **kwargs):
        self.sub = Sub(self)

当在第三类中使用 Foo 来处理特定的东西时:

class superFoo(Foo) :
    
    def specific(self,*a,**kw) :
        ...

我还想使用@decorator 将特定方法包装在子类中,就像我为 Foo 所做的那样:

from functools import wraps

def add_method(cls):
    def decorator(func):
        @wraps(func) 
        def wrapper(self, *args, **kwargs): 
            return func(self, *args, **kwargs)
        setattr(cls, func.__name__, wrapper)
    return decorator
    
@add_method(superFoo)
def spam(self, *args, **kwargs) :
    return self.specific() + ...
    
>>> inst = superFoo()
>>> inst.spam() # yep

但我想要的是这个:

>>> inst.sub.spam()

所以我尝试了:

@add_method(superFoo)
def spam(self, *args, **kwargs) :
    return self.inst.specific() + ...

在 add_method 函数中:

setattr(cls.sub, func.__name__, wrapper) # ouch, sub not instantiated

失败。

我可以继承 Sub(实际上我现在已经这样做了)来满足需求:

class superSub(Sub) :
    def spam(self, *args, **kwargs) :
        return self.inst.specific() + ...

class superFoo(Foo) :
    def __init__(self, *args, **kwargs):
        super().__init__(*args,**kwargs) # there is actualy other inheritances 
        self.sub = superSub(self) # replaces Sub() by its subclass

但我想知道我是否可以使用装饰器,如果可能的话,这样做:
add_method 将在需要时导入到模块中,并且模块的具体内容会一见钟情查看代码时:

from abyssal import add_method

class superFoo(Foo) : # folded in my editor

@add_method(superFoo) :
def spam(self) : # folded

非常感谢

【问题讨论】:

  • 你对装饰器的使用不是他们应该使用的方式(不是说它是错误的,它只是违反直觉)。它应该改变它所装饰的函数,而不是函数的参数。您能否提供更多详细信息,说明您为什么这样做。看来应该有更好的办法。
  • Sub() 类在 django 项目中的数十个 Foo() 子类中使用,并满足了大多数的需求。对于一种极端情况,我需要添加和覆盖一些 Sub() 方法,并且希望找到除继承/__init__/setattr 之外的其他方法。

标签: python class wrapper python-decorators functools


【解决方案1】:

您的 add_method 装饰器可以是您的 superFoo 类的方法:

class superFoo(Foo):

    def add_method(self):
        def decorator(func):
            setattr(self, func.__name__, func)
            return func
        return decorator

(注意我简化了一点)

然后你将它用作:

sub = Sub()
inst = superFoo(sub)

@inst.add_method(superFoo)
def spam(self, *args, **kwargs) :
    return self.inst.specific() + ...

但又一次。我建议使用继承。仅仅为Sub 定义子类会更简单、更容易理解。

【讨论】:

  • 我同意将 add_method 定义为 superFoo 方法没有附加价值,并且最好使用 init 通过子类覆盖 self.sub(我编辑我的问题以这种方式提及)。
猜你喜欢
  • 1970-01-01
  • 2017-09-14
  • 2017-12-04
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 1970-01-01
  • 2022-01-16
  • 2019-11-03
相关资源
最近更新 更多