我正在试验用Python实现简化术语重写系统(TRS)/Symbolic代数系统的方法。为此,我非常希望能够在类实例实例化过程中截获和修改特定情况下的操作数。我想出的解决方案是创建一个元类,以修改类对象的典型调用行为(类型为' 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)例如,扩展嵌套操作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结果表明,只有第一个预处理超类是“活动”。
print G(G(3,2,1),-1,-3).operands
(3,2,1,-1,-3)如何确保在类实例化之前调用所有预处理类的预处理方法?
更新:
由于我作为新的堆栈溢出用户的身份,我似乎还不能正式回答我的问题。因此,我相信这可能是我能想到的最好的解决方案:
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。
发布于 2012-05-15 23:00:30
我认为您这样做是错误的;放弃元类,而是使用类和方法修饰器。
例如,将您的单位定义为:
@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警告:所有以上代码都没有经过严格的测试。
https://stackoverflow.com/questions/10522431
复制相似问题