On Nov 21, 4:33 pm, Richard Thomas <chards...@gmail.com> wrote: > > This looks more structurally sound: > > class Node(object): > def eval(self): > raise NotImplementedError > def pprint(self): > raise NotImplementedError >
My objection to the interface you describe is that Node defines the type of operations that can be done to it by third-party code, which is something that I cannot predict, and which (pscouples every subclass of Node to eval() and pprint(), even though those subclasses might not care about either operation. They might be reimplementing only one of those operations, or some completely different operation. > > class Sum(BinaryOperatorNode): > operator = lambda x, y: x + y > > class Product(BinaryOperatorNode): > operator = lambda x, y: x * y > I do like the notion of driving up Sum/Product abstractions like "operator" into BinaryOperatorNode, but that is sort of an artifact of my toy example, not my main design dilemma. > I don't know what you're doing exactly but if all you need is to be > able to parse and evaluate expressions then you can get very decent > mileage out of overriding operators, to the extent that the whole > thing you are trying to do could be a single class... > > class Expression(object): > def __init__(self, func): > self.func = func > def __call__(self, **context): > while isinstance(self, Expression): > self = self.func(context) > return self > def __add__(self, other): > return Expression(lambda context: self.func(context) + other) > def __mul__(self, other): > [snipped] It is my fault for muddying the conversation with a toy example that evaluates arithmetic expressions. My particular problem involves a mini-language that describes how you want to descend Python data structures. > But maybe that's not what you need. No need to overengineer if it is > though, keep it simple, simple is better than complex. Yep! I am trying to keep things simple, but my wish to extend is not speculative at this point; it is real. I have an expression syntax, which I call pyDTL, that I want these operations on: * generate two different versions of Python code that expresses the operation * eagerly evaluate the expression on some object * pretty-print the expression itself * use the expression as a prototype for stub objects to determine what operations they allow * etc.... All of those requirements create the need to somehow create new objects or functions that correspond to the same AST. I describe pyDTL here: http://showellonprogramming.blogspot.com/2009/11/mini-ddl-for-python.html Here is a simple example: echo '{.foo, .bar(){.spam, .eggs} }' | python dtl/parse.py dict( foo = obj.foo, bar = (lambda bar: dict( spam = bar.spam, eggs = bar.eggs, ))(obj.bar()), ) ### -- http://mail.python.org/mailman/listinfo/python-list