Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:在类实例初始化之前修改传递的参数_Python_Oop_Multiple Inheritance_Metaclass - Fatal编程技术网

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

Python:在类实例初始化之前修改传递的参数,python,oop,multiple-inheritance,metaclass,Python,Oop,Multiple Inheritance,Metaclass,我正在试验用Python实现简化术语重写系统(TRS)/符号代数系统的方法。 为此,我非常希望能够在类实例实例化过程中的特定情况下拦截和修改操作数。 我提出的解决方案是创建一个元类,修改类对象(类型为“type”)的典型调用行为 一个例子是展开嵌套操作F(F(a,b),c)->F(a,b,c) 所以,现在这个行为可以通过继承来实现: class Operation(object): def __init__(self, *operands): self.operands

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

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

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

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
只会导致第一个预处理超类处于“活动”状态

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)。\uuu调用(*操作数,**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_预处理器decorator将该函数转换为类decorator:

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
现在,不再使用mixin,而是使用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

买主警告:以上所有代码都未经严格测试。

重写分配器并让它检查基数。嗯,这到底是如何工作的?在预处理中打印出cls对象的基。_call__方法产生(如预期的那样)(,)您需要返回动态类型的对象。这就是为什么要在分配器中执行此操作。所谓分配器,是指“\uuuu new\uuuuu()”方法吗?我以前是这样做的,但问题是,如果我在新方法中更改操作数,但返回相同类型的对象,构造函数(init)将接收原始未处理的操作数作为其参数…分配器的全部目的是生成一个全新的类型。嗨,是的,这看起来是一个非常好的解决方案,事实证明,我现在实际上正在沿着这些思路做一些事情。其中一个问题是对象“G”不再是类,而是函数,因此isinstance()检查将在不进一步调整的情况下失败。为什么
G
是函数?它仅由类装饰器修改
@init_args_预处理器
flat
转换为一个函数,该函数接受一个类并返回一个类。糟糕,你是对的。事实上,我就是这样做的。
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