On Sun, 13 Nov 2005 17:31:32 +0100, Reinhold Birkenfeld <[EMAIL PROTECTED]> wrote:
>[EMAIL PROTECTED] wrote: >> Tom Anderson: >>> And we're halfway to looking like perl already! Perhaps a more pythonic >>> thing would be to define a "then" operator: >>> all_lines = file1 then file2 then file3 >> >> Or a "chain" one: >>> all_lines = file1 chain file2 chain file3 > >That's certainly not better than the chain() function. Introducing new >operators >for just one application is not pythonic. Agreed. But here's a thought: What if expr1 expr2 were as legal as expr1, expr2 and had well defined meaning? The meaning I have in mind is that expr1 and expr2 (etc if more) should be evaluated just as they are for building a tuple. Then, instead of taking the values on the stack and building the tuple, the whole sequence is evaluated by looking for three possible methods on the objects. First, a __unaryop__ method is sought. If present, that is sufficient to evaluate expr1 expr2 as expr1.__unaryop__(expr2) Now that effectively becomes the first element replacing the first two elements of the sequence. If it is the only element, that is the value of the whole. If there are more elements, we start as if with a new sequence, so expr1 expr2 expr2 is equivalent to (expr1 expr2 expr3) is equivalent to ((expr1 expr2) expr3) so we evaluate (expr1 expr2).__unaryop__(expr3) if that __unaryop__ exists. If not, we look for a postfix unary op method on expr3 and if present, we get expr3.__pfunaryop__((expr1 expr2)) as the value of the whole. Or to write it out fully, expr3.__pfunaryop__(expr1.__unaryop__(expr2)) Now if expr1 had no op method, we would look for __pfunaryop__ on expr2 and if found the value would obviously be expr2.__pfunaryop__(expr1) If there is no __pfunaryop__ on expr2, we look for a __binaryop__ method, (BTW meaning unary ops are given precedence). If we have expr2.__binaryop__, then we need an expr3, or it is an error. If present, we get a value for expr1 expr2 expr3 that is expr2.__binaryop__(expr1, expr3) Now if e.g. a bare-name expression MINUS is bound to an object that has both a __unaryop__ and a __binaryop__ method, parens can as usual control the evaluation. E.g., MINUS a MINUS b evaluates to MINUS.__binaryop__(MINUS.__unaryop__(a), b) whereas MINUS (a MINUS b) evaluates to MINUS.__unaryop__(MINUS.__binaryop__(a, b)) Presumably the byte codes for the above would look something like (faked!! minor revision of tuple-building code ;-) >>> dis.dis(compile('MINUS a MINUS b','','eval')) 0 0 LOAD_NAME 0 (MINUS) 3 LOAD_NAME 1 (a) 6 LOAD_NAME 0 (MINUS) 9 LOAD_NAME 2 (b) 12 EVAL_EXPR_SEQ 4 15 RETURN_VALUE >>> dis.dis(compile('MINUS (a MINUS b)','','eval')) 0 0 LOAD_NAME 0 (MINUS) 3 LOAD_NAME 1 (a) 6 LOAD_NAME 0 (MINUS) 9 LOAD_NAME 2 (b) 12 EVAL_EXPR_SEQ 3 15 EVAL_EXPR_SEQ 2 18 RETURN_VALUE I think this might have some interesting possibilities ;-) I'm sure there can be some interesting ambiguities in the syntax of adjacent blank-separated expressions, but nothing parens couldn't overcome, IWT. Built-in operators with symbols such as +, -, *, / etc. would of course not be treated as as objects in the above sense. I.e., even if expr1 had a __unaryop__ method, expr1 - expr2 could not become expr1.__unaryop__(-expr2) unless you forced the issue with expr1 (-expr2) Ok, this should be fun ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list