将函数包装为python中类的子类中的方法



这里是(简化的(情况:

我有一个包含子类的类:

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

非常感谢

您的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定义子类会简单得多,也更容易理解。

老兄,你想要的是让inst.spam((工作起来,对吧?spam((必须使用inst属性才能工作。我想你说得对。请尝试以下代码。

class Foo:
class Sub:
def __init__(self, object) -> None:
self.object = object

def spam(self):
print('I print a Foo attribute')
print('Foo attribute is:', self.object.name)


def __init__(self):
self.name = 'foo'
self.sub = Foo.Sub(self)

inst = Foo()  
inst.sub.spam()

最新更新