Lance, Sorry if I am being a pain in the #%%, I just want to make sure that we get the desig of this right as someone else said "you only get to implement __call__ once". I do appreciate you willingness to do the implementation of this and hear me out. A few things about this most recent patch:
The patch allows __call__ to be used in the following ways: + >>> f = 1+x*y + >>> f(x=pi,y=2) + 1 + 2*pi This is great and I think we all agree that this absolutely should be supported. +1 on this. + >>> f({x:pi, y:2}) + 1 + 2*pi I am +0 on this. The main thing that I am guided by is that __call__ should be used to implement something that looks like a function call (in the mathematical sense). The mathematician in me sees this and asks, how do I can a function with a dictionary? + >>> f([(x,pi),(y,2)]) + 1 + 2*pi I am -1 on this. Try to forget about subs for a second. Most new users will want to use a function call syntax before they do a subs (I am thinking of my students in the physics department). This syntax is _very_ confusing for someone expecting function calls to behave like they do in math. Also, it violates this (pun intended): >>> import this ... There should be one-- and preferably only one --obvious way to do it. ... For function calling that involves key/value pairs f(x=1,y=3) already works just fine. As an aside, this is also a complaint that I have about subs - we have a single function that can be called in (it seems 10 different ways. It that really needed. Simplify, simplify, sympify. Other thoughts? Brian On Tue, Nov 18, 2008 at 8:20 PM, Lance Larsen <[EMAIL PROTECTED]> wrote: > > # HG changeset patch > # User "Lance Larsen <[EMAIL PROTECTED]>" > # Date 1226946818 25200 > # Node ID 060b92b72467a29a2d098e7ce0ee96cbf4c2395b > # Parent d1019a5c66d12d524fe64359c1bd8054cab0cfa9 > Substitution syntax extension - implements f.subs(x=1,y=2) and > shorthand syntax f(x=1,y=2). > > diff -r d1019a5c66d1 -r 060b92b72467 sympy/core/basic.py > --- a/sympy/core/basic.py Tue Nov 18 17:36:24 2008 +0100 > +++ b/sympy/core/basic.py Mon Nov 17 11:33:38 2008 -0700 > @@ -896,26 +896,43 @@ > """ > return self > > - def subs(self, *args): > + def subs(self, *args, **kwargs): > """ > Substitutes an expression. > > Calls either _subs_old_new, _subs_dict or _subs_list > depending > - if you give it two arguments (old, new), a dictionary or a > list. > + if you give it two arguments (old, new), a dictionary, a list > or > + pass in named parameters. When named parameters are passed > in, > + these are converted to a dictionary and _subs_dict is called. > > Examples: > > >>> from sympy import * > >>> x,y = symbols('xy') > - >>> (1+x*y).subs(x, pi) > - 1 + pi*y > + >>> (1+x*y).subs(x=pi, y=2) > + 1 + 2*pi > >>> (1+x*y).subs({x:pi, y:2}) > 1 + 2*pi > >>> (1+x*y).subs([(x,pi), (y,2)]) > 1 + 2*pi > + >>> (1+x*y).subs(x, pi) > + 1 + pi*y > + > + Subs can be called implicitly as well as shown in the > following > + examples: > + > + >>> f = 1+x*y > + >>> f(x=pi, y=2) > + 1 + 2*pi > + >>> f({x:pi, y:2}) > + 1 + 2*pi > + >>> f([(x,pi), (y,2)]) > + 1 + 2*pi > + >>> f(x, pi) > + 1 + pi*y > > """ > - if len(args) == 1: > + if len(args) == 1 and len(kwargs) == 0: > sequence = args[0] > if isinstance(sequence, dict): > return self._subs_dict(sequence) > @@ -923,9 +940,11 @@ > return self._subs_list(sequence) > else: > raise TypeError("Not an iterable container") > - elif len(args) == 2: > + elif len(args) == 2 and len(kwargs) == 0: > old, new = args > return self._subs_old_new(old, new) > + elif len(args) == 0 and len(kwargs) > 0: > + return self._subs_dict(kwargs) > else: > raise Exception("subs accept either 1 or 2 arguments") > > @@ -1932,9 +1951,25 @@ > from sympy.integrals import integrate > return integrate(self, *args, **kwargs) > > - #XXX fix the removeme > - def __call__(self, *args, **removeme): > - return Function(self[0])(*args) > + def __call__(self, *args, **kwargs): > + """Alias for calling the subs function. All subs syntax is > supported > + the two parameter syntax f(x,2) for f(x=2). > + > + Examples: > + > + >>> from sympy import * > + >>> x,y = symbols('xy') > + >>> f = 1+x*y > + >>> f(x=pi,y=2) > + 1 + 2*pi > + >>> f({x:pi, y:2}) > + 1 + 2*pi > + >>> f([(x,pi),(y,2)]) > + 1 + 2*pi > + """ > + if len(args) > 1: > + raise Exception("Unsupported syntax. Pass a dictionary, a > list of substitution pairs, or name=value pairs.") > + return self.subs(*args, **kwargs) > > def __float__(self): > result = self.evalf() > diff -r d1019a5c66d1 -r 060b92b72467 sympy/core/tests/test_subs.py > --- a/sympy/core/tests/test_subs.py Tue Nov 18 17:36:24 2008 +0100 > +++ b/sympy/core/tests/test_subs.py Mon Nov 17 11:33:38 2008 -0700 > @@ -169,3 +169,16 @@ > assert (f(x,y)).subs(f,sin) == f(x,y) > assert (sin(x)+atan2(x,y)).subs([[atan2,f],[sin,g]]) == f(x,y) + g > (x) > assert (g(f(x+y, x))).subs([[f, l], [g, exp]]) == exp(x + sin(x + > y)) > + > +def test_subs_call_syntax(): > + a, b, x, y, p, q = map(Symbol, "abxypq") > + f = 2*a*x+3*b*y > + assert f(x=1, y=2) == 2*a + 6*b > + assert f({a*x:p,b*y:q}) == 2*p + 3*q > + > +def test_implicit_subs_call_syntax(): > + a, b, x, y, p, q = map(Symbol, 'abxypq') > + f = 2*a*x + 3*b*y > + assert f(x=1, y=2) == 2*a + 6*b > + assert f({a*x:p,b*y:q}) == 2*p + 3*q > + assert f([(a*x,p),(b*y,q)]) == 2*p + 3*q > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sympy-patches" group. To post to this group, send email to sympy-patches@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sympy-patches?hl=en -~----------~----~----~----~------~----~------~--~---