1 | | Let {{{e}}} be a symbolic expression. It may happen that {{{e.operator()}}} has a certain callable attribute, say, {{{foo}}}, that is not a method of {{{Function}}}. In this situation, one would like to use {{{e.foo()}}}, which is supposed to return {{{e.operator().foo(*e.operands())}}} - apparently this is useful for working with hypergeometric functions. |
| 1 | Let {{{e}}} be a symbolic expression. It may happen that {{{e.operator()}}} has a certain callable attribute, say, {{{foo}}}, that is not a method of {{{Function}}}. In this situation, one would like to use {{{e.foo()}}}, which is supposed to return {{{e.operator().foo(*e.operands())}}} - apparently this is useful for working with hypergeometric functions (#2516). |
6 | | sage: from sage.symbolic.function import BuiltinFunction |
7 | | sage: class ExampleBuiltin(BuiltinFunction): |
8 | | ... def __init__(self): |
9 | | ... BuiltinFunction.__init__(self, 'ex_func', nargs=0) #arbitrary no of args |
10 | | ... def some_function_name(self, *args): |
11 | | ... return len(args) |
12 | | ... |
13 | | sage: ex_func = ExampleBuiltin() |
14 | | sage: ex_func |
15 | | ex_func |
| 6 | sage: from sage.symbolic.function import BuiltinFunction |
| 7 | sage: class TFunc(BuiltinFunction): |
| 8 | ....: def __init__(self): |
| 9 | ....: BuiltinFunction.__init__(self, 'tfunc', nargs=1) |
| 10 | ....: |
| 11 | ....: class EvaluationMethods: |
| 12 | ....: def argp1(self, x): |
| 13 | ....: ''' |
| 14 | ....: Some documentation about a bogus function. |
| 15 | ....: ''' |
| 16 | ....: return x+1 |
| 17 | ....: |
| 18 | ....: @property |
| 19 | ....: def foo(self): |
| 20 | ....: return 5 |
| 21 | ....: |
| 22 | sage: tfunc = TFunc() |
| 23 | sage: e = tfunc(x); e |
| 24 | tfunc(x) |
| 25 | sage: type(e) |
| 26 | <class '__main__.Expression_with_dynamic_methods'> |
| 27 | sage: e.argp1() |
| 28 | x + 1 |
| 29 | sage: e.foo |
| 30 | 5 |
| 31 | sage: x.argp1() |
| 32 | Traceback (most recent call last): |
| 33 | ... |
| 34 | AttributeError: 'sage.symbolic.expression.Expression' object has no |
| 35 | attribute 'argp1' |
| 36 | sage: t = (e + 1).op[0]; t |
| 37 | tfunc(x) |
| 38 | sage: t |
| 39 | tfunc(x) |
| 40 | sage: type(t) |
| 41 | <class '__main__.Expression_with_dynamic_methods'> |
| 42 | sage: t.argp1() |
| 43 | x + 1 |
| 44 | sage: import sagenb.misc.support as s |
| 45 | sage: s.completions('t.argp', globals(), system='python') |
| 46 | ['t.argp1'] |
| 47 | sage: t.argp1.__doc__.strip() |
| 48 | 'Some documentation about a bogus function.' |
18 | | We obtain a symbolic expression by calling {{{ex_func}}}: |
19 | | {{{ |
20 | | sage: e = ex_func(x,x+1, x+2) |
21 | | sage: type(e) |
22 | | <type 'sage.symbolic.expression.Expression'> |
23 | | }}} |
24 | | |
25 | | We add a callable and a non-callable attribute to {{{ex_func}}}: |
26 | | {{{ |
27 | | sage: def some_function(slf, *L): print slf,'called with',L |
28 | | ... |
29 | | sage: ex_func.foo_bar = some_function |
30 | | sage: ex_func.bar_foo = 4 |
31 | | }}} |
32 | | |
33 | | Now, both the new method and the callable attribute {{{foo_bar}}} of |
34 | | {{{ex_func}}} are available from {{{e}}}, but not the non-callable: |
35 | | |
36 | | {{{ |
37 | | sage: e.some_function_name() |
38 | | 3 |
39 | | sage: e.foo_bar() |
40 | | ex_func called with (x, x + 1, x + 2) |
41 | | sage: e.bar_foo |
42 | | Traceback (most recent call last): |
43 | | ... |
44 | | AttributeError: <type 'sage.symbolic.expression.Expression'> has no attribute 'bar_foo' |
45 | | }}} |
46 | | |
47 | | Tab completion and introspection work: |
48 | | |
49 | | {{{ |
50 | | sage: 'foo_bar' in dir(e) # indirect doctest |
51 | | True |
52 | | sage: 'some_function_name' in dir(e) |
53 | | True |
54 | | sage: 'bar_foo' in dir(e) |
55 | | False |
56 | | sage: import sagenb.misc.support as s |
57 | | sage: s.completions('e.some', globals(), system='python') |
58 | | ['e.some_function_name'] |
59 | | }}} |
60 | | |
61 | | '''__Problems__''' |
62 | | |
63 | | When I ran {{{sage -testall}}}, several doctests segfaulted: |
64 | | {{{ |
65 | | sage -t -verbose "devel/sage/sage/functions/hyperbolic.py" |
66 | | sage -t -verbose "devel/sage/sage/games/hexad.py" |
67 | | sage -t -verbose "devel/sage/sage/matrix/tests.py" |
68 | | sage -t -verbose "devel/sage/sage/misc/sage_eval.py" |
69 | | sage -t -verbose "devel/sage/sage/plot/animate.py" |
70 | | sage -t -verbose "devel/sage/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py" |
71 | | sage -t -verbose "devel/sage/sage/rings/polynomial/polynomial_element.pyx" |
72 | | }}} |
73 | | |
74 | | I tried (using {{{sage -t -verbose}}}) to find out what exactly fails. When I ran some of these failing examples in an interactive session, no segfault occured. So, is there a nasty side effect? |
| 51 | Apply: [[attachment:trac_9556-dynamic_class_everywhere.patch]] |