Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# Copyright (c) 2009, Tom Boothby <boothby@math.washington.edu> # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of Sage nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY Tom Boothby ''AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL Tom Boothby BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
Function Mangling
This module provides utilities for extracting information about python functions.
AUTHORS:
- Tom Boothby (2009): Original version in Python - Simon King (2011): Use Cython. Speedup of ``fix_to_pos``, cleaning documentation.
""" from __future__ import print_function
from sage.misc.sageinspect import sage_getargspec
cdef class ArgumentFixer: """ This class provides functionality to normalize the arguments passed into a function. While the various ways of calling a function are perfectly equivalent from the perspective of the callee, they don't always look the same for an object watching the caller. For example, ::
sage: def f(x = 10): ....: return min(1,x)
the following calls are equivalent, ::
sage: f() 1 sage: f(10) 1 sage: f(x=10) 1
but from the perspective of a wrapper, they are different::
sage: def wrap(g): ....: def _g(*args,**kwargs): ....: print("{} {}".format(args, kwargs)) ....: return g(*args, **kwargs) ....: return _g sage: h = wrap(f) sage: t = h() () {} sage: t = h(10) (10,) {} sage: t = h(x=10) () {'x': 10}
For the purpose of cached functions, it is important not to distinguish between these uses.
INPUT:
- f -- a function - classmethod -- boolean (default False) -- True if the function is a classmethod and therefore the first argument is expected to be the class instance. In that case, we ignore the first argument.
EXAMPLES::
sage: from sage.misc.function_mangling import ArgumentFixer sage: def wrap2(g): ....: af = ArgumentFixer(g) ....: def _g(*args, **kwargs): ....: print(af.fix_to_pos()) ....: return g(*args,**kwargs) ....: return _g sage: h2 = wrap2(f) sage: t = h2() ((10,), ()) sage: t = h2(10) ((10,), ()) sage: t = h2(x=10) ((10,), ())
::
sage: class one: ....: def __init__(self, x = 1): ....: self.x = x sage: af = ArgumentFixer(one.__init__.__func__, classmethod=True) sage: af.fix_to_pos(1,2,3,a=31,b=2,n=3) ((1, 2, 3), (('a', 31), ('b', 2), ('n', 3)))
""" def __init__(self, f, classmethod = False): except AttributeError: # This error occurs if f is defined in a Cython file and the # source file has gone. if classmethod: arg_names = ['self'] varargs = 'args' varkws = 'kwds' defaults = None else: arg_names = [] varargs = 'args' varkws = 'kwds' defaults = None else:
#code = f.__code__
else:
cdef dict default_map
def __repr__(self): """ EXAMPLES::
sage: from sage.misc.function_mangling import ArgumentFixer sage: g = ArgumentFixer(number_of_partitions) sage: g Argument Fixer of <function number_of_partitions at 0x...> """
def fix_to_named(self, *args,**kwargs): """ Normalize the arguments with a preference for named arguments.
INPUT:
- any positional and named arguments.
OUTPUT:
We return a tuple
`(e_1, e_2, ..., e_k), ((n_1, v_1), ... , (n_m, v_m))`
where `n_1, ... , n_m` are the names of the arguments and `v_1, ..., v_m` are the values passed in; and `e_1, ..., e_k` are the unnamed arguments. We minimize `k`.
The defaults are extracted from the function and filled into the list ``K`` of named arguments. The names `n_1, ..., n_t` are in order of the function definition, where `t` is the number of named arguments. The remaining names, `n_{t+1}, ..., n_m` are given in alphabetical order. This is useful to extract the names of arguments, but **does not** maintain equivalence of ::
A,K = self.fix_to_pos(...) self.f(*A,**dict(K))`
and ::
self.f(...)
in all cases.
EXAMPLES::
sage: from sage.misc.function_mangling import ArgumentFixer sage: def sum3(a,b,c=3,*args,**kwargs): ....: return a+b+c sage: AF = ArgumentFixer(sum3) sage: AF.fix_to_named(1,2,3,4,5,6,f=14,e=16) ((4, 5, 6), (('a', 1), ('b', 2), ('c', 3), ('e', 16), ('f', 14))) sage: AF.fix_to_named(1,2,f=14) ((), (('a', 1), ('b', 2), ('c', 3), ('f', 14)))
""" cdef int i else: else:
def fix_to_pos(self, *args, **kwds): """ Normalize the arguments with a preference for positional arguments.
INPUT:
Any positional or named arguments
OUTPUT:
We return a tuple
`(e_1, e_2, ..., e_k), ((n_1, v_1), ... , (n_m, v_m))`
where `n_1, ... , n_m` are the names of the arguments and `v_1, ..., v_m` are the values passed in; and `e_1, ..., e_k` are the unnamed arguments. We minimize `m`.
The commands ::
A,K = self.fix_to_pos(...) self.f(*A,**dict(K))
are equivalent to ::
self.f(...)
though defaults are extracted from the function and appended to the tuple ``A`` of positional arguments. The names `n_1, ..., n_m` are given in alphabetical order.
EXAMPLES::
sage: from sage.misc.function_mangling import ArgumentFixer sage: def do_something(a, b, c=3, *args, **kwargs): ....: print("{} {} {} {} {}".format(a, b, c, args, ....: sorted(kwargs.items()))) sage: AF = ArgumentFixer(do_something) sage: A, K = AF.fix_to_pos(1, 2, 3, 4, 5, 6, f=14, e=16) sage: print("{} {}".format(A, K)) (1, 2, 3, 4, 5, 6) (('e', 16), ('f', 14)) sage: do_something(*A, **dict(K)) 1 2 3 (4, 5, 6) [('e', 16), ('f', 14)] sage: do_something(1, 2, 3, 4, 5, 6, f=14, e=16) 1 2 3 (4, 5, 6) [('e', 16), ('f', 14)] """
cdef fix_to_pos_args_kwds(self, tuple args, dict kwds): """ Fast Cython implementation of :meth:`fix_to_pos`. """ # a shortpath for the case of no named arguments: # we take the given arguments, plus the default arguments cdef Py_ssize_t i # in addition to the positional arguments, we take the # ones with default values, unless they are overridded by # the named arguments. else: |