包装python超类的所有方法 [英] Wrap all methods of python superclass

查看:60
本文介绍了包装python超类的所有方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我不能更改其代码,是否可以包装超类的所有方法?

Is there a way to wrap all methods of a superclass, if I can't change its code?

作为一个最小的工作示例,请考虑这个基类 Base ,它具有许多返回自身新实例的方法以及后代类 Child

As a minimal working example, consider this base class Base, which has many methods that return a new instance of itself, and the descendent class Child

class Base:
    
    def __init__(self, val):
        self.val = val
        
    def newinst_addseven(self):
        return Base(self.val + 7)
    
    def newinst_timestwo(self):
        return Base(self.val * 2)
    
    # ...

class Child(Base):
    
    @property
    def sqrt(self):
        return math.sqrt(self.val)

这里的问题是,调用 childinstance.newinst_addseven()会返回 Base 的实例,而不是 Child .

The issue here is that calling childinstance.newinst_addseven() returns an instance of Base, instead of Child.

是否可以包装 Base 类的方法以强制返回 Child 类型的返回值?

Is there a way to wrap the Base class's methods to force a return value of the type Child?

使用类似这种包装的东西:

With something like this wrapper:

def force_child_i(result):
    """Turn Base instance into Child instance."""
    if type(result) is Base:
        return Child(result.val)
    return result

def force_child_f(fun):
    """Turn from Base- to Child-instance-returning function."""
    def wrapper(*args, **kwargs):
        result = fun(*args, **kwargs)
        return force_child_i(result)
    return wrapper

非常感谢!

PS:我目前正在做的是查看 Base 的源代码并将方法直接添加到 Child 中,这不是很容易维护:

PS: What I currently do, is look at Base's source code and add the methods to Child directly, which is not very mainainable:

Child.newinst_addseven = force_child_f(Base.newinst_addseven)
Child.newinst_timestwo = force_child_f(Base.newinst_timestwo)

推荐答案

一种选择是使用元类:

class ChildMeta(type):
    def __new__(cls, name, bases, dct):
        child = super().__new__(cls, name, bases, dct)
        for base in bases:
            for field_name, field in base.__dict__.items():
                if callable(field):
                    setattr(child, field_name, force_child(field))
        return child


class Child(Base, metaclass=ChildMeta):
    pass

它将使用您的 force_child 装饰器自动包装所有 Base 的方法.

It will automatically wrap all the Bases methods with your force_child decorator.

这篇关于包装python超类的所有方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆