Skip to main content
 首页 » 编程设计

Python:在类实例初始化之前修改传递的参数

2025年05月04日7TianFang

我正在试验用 Python 实现简化的术语重写系统 (TRS)/符号代数系统的方法。 为此,我真的很希望能够在类实例实例化过程中拦截和修改特定情况下的操作数。 我想到的解决方案是创建一个元类来修改类对象(“类型”类型)的典型调用行为。

class Preprocess(type): 
    """ 
    Operation argument preprocessing Metaclass. 
    Classes using this Metaclass must implement the  
        _preprocess_(*operands, **kwargs) 
    classmethod. 
    """ 
 
    def __call__(cls, *operands, **kwargs): 
        pops, pargs = cls._preprocess_(*operands, **kwargs) 
        return super(Preprocess, cls).__call__(*pops, **pargs) 

一个例子是扩展嵌套操作 F(F(a,b),c)-->F(a,b,c)

class Flat(object): 
    """ 
    Use for associative Operations to expand nested  
    expressions of same Head: F(F(x,y),z) => F(x,y,z) 
    """ 
    __metaclass__ = Preprocess 
    @classmethod 
    def _preprocess_(cls, *operands, **kwargs): 
        head = [] 
        for o in operands: 
            if isinstance(o, cls): 
                head += list(o.operands) 
            else: 
                head.append(o) 
        return tuple(head), kwargs 

那么,现在这个行为可以通过继承来实现:

class Operation(object): 
    def __init__(self, *operands): 
        self.operands = operands 
 
class F(Flat, Operation): 
    pass 

这会导致所需的行为:

print F(F(1,2,3),4,5).operands 
(1,2,3,4,5) 

但是,我想组合几个这样的预处理类,让它们按照自然类mro顺序处理操作数。

class Orderless(object): 
    """ 
    Use for commutative Operations to bring into ordered, equivalent  
    form: F(*operands) => F(*sorted(operands)) 
    """ 
    __metaclass__ = Preprocess 
 
    @classmethod 
    def _preprocess_(cls, *operands, **kwargs): 
 
        return sorted(operands), kwargs 

这似乎并没有按预期工作。定义扁平无序操作类型

class G(Flat, Orderless, Expression): 
    pass 

仅导致第一个预处理父类(super class)处于“事件”状态。

print G(G(3,2,1),-1,-3).operands 
(3,2,1,-1,-3) 

如何确保在类实例化之前调用所有预处理类的预处理方法?

更新:

由于我是新的 stackoverflow 用户,我似乎还不能正式回答我的问题。 所以,我相信这可能是我能想到的最佳解决方案:

class Preprocess(type): 
    """ 
    Abstract operation argument preprocessing class. 
    Subclasses must implement the  
        _preprocess_(*operands, **kwargs) 
    classmethod. 
    """ 
 
    def __call__(cls, *operands, **kwargs): 
        for cc in cls.__mro__: 
            if hasattr(cc, "_preprocess_"): 
                operands, kwargs = cc._preprocess_(*operands, **kwargs) 
 
        return super(Preprocess, cls).__call__(*operands, **kwargs) 

我猜问题是 super(Preprocess, cls).__call__(*operands, **kwargs) 没有按预期遍历 cls 的 mro。

请您参考如下方法:

我认为你的做法是错误的;删除元类,改用类和方法装饰器。

例如,将您的公寓定义为:

@init_args_preprocessor 
def flat(operands, kwargs): # No need for asterisks 
    head = [] 
    for o in operands: 
        if isinstance(o, cls): 
            head += list(o.operands) 
        else: 
            head.append(o) 
    return tuple(head), kwargs 

使用 init_args_preprocessor 装饰器将该函数转换为类装饰器:

def init_args_preprocessor(preprocessor): 
    def class_decorator(cls): 
        orig_init = cls.__init__ 
        def new_init(self, *args, **kwargs): 
            args, kwargs = preprocessor(args, kwargs) 
            orig_init(self, *args, **kwargs) 
        cls.__init__ = new_init 
        return cls 
   return class_decorator 

现在,使用装饰器代替混合:

class Operation(object): 
    def __init__(self, *operands): 
        self.operands = operands 
 
@flat 
class F(Operation): 
    pass 

而且你应该没有问题干净地组合类修饰符:

@init_args_preprocessor 
def orderless(args, kwargs): 
    return sorted(args), kwargs 
 
@orderless 
@flat 
class G(Expression): 
   pass 

买者自负:以上所有代码均未经严格测试。