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

I am experimenting with ways to implement a simplified Term Rewriting System (TRS)/Symbolic Algebra System in Python.

For this I would really like to be able to be able to intercept and modify the operands in particular cases during the class instance instantiation process.

The solution I came up with, was to create a metaclass that modifies the typical call behavior of a class object (of type 'type').

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)

An example case would be to expand out nested operations 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

So, now this behavior can be realized through inheritance:

class Operation(object):

def __init__(self, *operands):

self.operands = operands

class F(Flat, Operation):

pass

This leads to the desired behavior:

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

(1,2,3,4,5)

However, I would like to combine several such preprocessing classes and have them process the operands sequentially according to the natural class 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

And this does not seem to work as wanted. Defining a Flat and Orderless Operation type

class G(Flat, Orderless, Expression):

pass

results in only the first Preprocessing superclass being 'active'.

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

(3,2,1,-1,-3)

How can I ensure that all Preprocessing classes' preprocess methods are called before class instantiation?

Update:

I can't seem to formally answer my question yet due to my status as new stackoverflow user.

So, I believe this is probably the best solution I can come up with:

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)

I guess the problem is that super(Preprocess, cls).__call__(*operands, **kwargs) does not traverse the mro of cls as expected.

解决方案

I think you're going about this the wrong way; drop the metaclass, use class and method decorators instead.

For example, define your flat as:

@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

With the init_args_preprocessor decorator turning that function into a class 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

And now, instead of mixins use decorators:

class Operation(object):

def __init__(self, *operands):

self.operands = operands

@flat

class F(Operation):

pass

And you should have no problem combining the class modifiers cleanly:

@init_args_preprocessor

def orderless(args, kwargs):

return sorted(args), kwargs

@orderless

@flat

class G(Expression):

pass

Caveat Emptor: All code above strictly untested.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值