Pass only one variable to a function in Python - python

Let's say I have the function
def f(x,y):
return x+y
and I want to create a function that returns a function in which a specific variable is passed:
def G(f,n,q): #a function in which the n-th variable of function f is passed the value q
return ??
The question is: how should I define G?
For example, G(f,0,1) should return the function f in which variable 0 is passed the value one. In other words, G(f,0,1) should behave as g, which I define by
def g(x):
return f(1,x)

In that case you can construct a function that construct a function. Like:
def G(f,n,q):
def h(*args):
ls = list(args)
ls.insert(n,q)
return f(*ls)
return h
You thus construct a function h that takes as input an arbitrary number of elements *args. Then you convert it to a list(..) such that you can alter the list. Next you insert the given parameter q as index n into the list, and you pass that list with an asterisk to the given function f.

Here's a smaller, simpler, related working example. In general, you might want to read about python decorators and partial functions.
>>> def power(x):
... def foo(y):
... return y**x
... return foo
...
>>> square = power(2)
>>> cube = power(3)
>>> square(2)
4
>>> square(3)
9
>>> cube(2)
8
>>> cube(3)
27
>>>

You can take a look at the functools module.
For example, using the partial method you can do:
from functools import partial
def G(f, n, q):
return partial(f, n=q)
This replaces the keyword argument named n withq
You could also replace positional arguments but they have to be in order:
from functools import partial
def G(f, n, q):
return partial(f, q)
This replaces the first argument with q

Related

How to print the __doc__ string of a function inside the function without specifying the name of the function

Lets say I have a function like this:
def square(n):
'''Takes in a number n, returns the square of n'''
how_can_I_do_this = __doc__
Is there any way I get the __doc__ string without mentioning the function name? That is, how do I print the __doc__ string of a function inside the function without specifying the name of the function?
reference:
How to print Docstring of python function from inside the function itself?
code:
import inspect
def square(n):
'''Takes in a number n, returns the square of n'''
print(inspect.getdoc(globals()[inspect.getframeinfo(inspect.currentframe()).function]))
square(0)
result:
Takes in a number n, returns the square of n
You can make use of built-in library inspect to get the required info. You can use it to getinfo about the caller also (which you mention in your comment). Please see example below:
import inspect
def sq(num):
'''returns square of number'''
info = inspect.stack()
current = globals()[info[0].function]
caller = globals()[info[1].function]
print(current.__doc__)
print(caller.__doc__)
return num*num
def call_sq(num):
'''calls sq with num'''
ans = sq(num)
return ans
def print_sq(num):
'''calls call_sq to get ans and prints it'''
ans = call_sq(num)
print(f'Square of {num} is {ans}')
print_sq(5)
Running this gives me:
returns square of number
calls sq with num
Square of 5 is 25
You could create a function decorator, similar to below:
def get_docstring(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs), func.__doc__
return wrapper
#get_docstring
def square(n):
"""
Returns the square of n
"""
return n ** 2
When calling the square() function:
>>> square(5)
(25, '\n\tReturns the square of n\n\t')
>>> res, doc = square(5)
>>> res
25
>>> doc
'\n\tReturns the square of n\n\t'
>>> print(doc)
Returns the square of n
For print the docstring inside the function, just pass func.__doc__ before passing **kwargs inside wrapper():
def get_docstring(func):
def wrapper(*args, **kwargs):
return func(*args, func.__doc__, **kwargs)
return wrapper
#get_docstring
def square(n, doc):
"""
Returns the square of n
"""
print(doc)
return n ** 2
When calling the square() function:
>>> square(5)
Returns the square of n
25

How to specify arg position for functool partial()

As per manual, functools partial() is 'used for partial function application which “freezes” some portion of a function’s arguments and/or keywords resulting in a new object with a simplified signature.'
What's the best way to specify the positions of the arguments that one wishes to evaluate?
EDIT
Note as per comments, the function to be partially evaluated may contain named and unnamed arguments (these functions should be completely arbitrary and may be preexisting)
END EDIT
For example, consider:
def f(x,y,z):
return x + 2*y + 3*z
Then, using
from functools import partial
both
partial(f,4)(5,6)
and
partial(f,4,5)(6)
give 32.
But what if one wants to evaluate, say the third argument z or the first and third arguments x, and z?
Is there a convenient way to pass the position information to partial, using a decorator or a dict whose keys are the desired arg positions and the respective values are the arg values? eg to pass the x and z positions something like like this:
partial_dict(f,{0:4,2:6})(5)
No, partial is not designed to freeze positional arguments at non-sequential positions.
To achieve the desired behavior outlined in your question, you would have to come up with a wrapper function of your own like this:
def partial_positionals(func, positionals, **keywords):
def wrapper(*args, **kwargs):
arg = iter(args)
return func(*(positionals[i] if i in positionals else next(arg)
for i in range(len(args) + len(positionals))), **{**keywords, **kwargs})
return wrapper
so that:
def f(x, y, z):
return x + 2 * y + 3 * z
print(partial_positionals(f, {0: 4, 2: 6})(5))
outputs:
32
Simply use keyword arguments. Using your definition of f above,
>>> g = partial(f, z=10)
>>> g(2, 4)
40
>>> h = partial(f, y=4, z=10)
>>> h(2)
40
Note that once you use a keyword argument for a given parameter, you must use keyword arguments for all remaining arguments. For example, the following would not be valid:
>>> j = partial(f, x=2, z=10)
>>> j(4)
TypeError: f() got multiple values for argument 'x'
But continuing to use keyword arguments is:
>>> j = partial(f, x=2, z=10)
>>> j(y=4)
40
When you use functools.partial, you store the values of *args and **kwargs for later interpolation. When you later call the "partially applied" function, the implementation of functools.partial effectively adds the previously provided *args and **kwargs to the argument list at the front and end, respectively, as though you had inserted these argument-unpackings yourself. I.e., calling
h = partial(1, z=10)
f(4)
is roughly equivalent to writing
args = [1]
kwargs = {'z': 10}
f(*args, 4, **kwargs)
As such, the semantics of how you provide arguments to functools.partial is the same as how you would need to store arguments in the args and kwargs variables above such that the final call to f is sensible. For more information, take a look at the pseduo-implementation of functools.partial given in the functools module documentation
For easier usage, you can create a new object specifically to specify a positional argument that is to be skipped when sequentially listing values for positional arguments to be frozen with partial:
SKIP = object()
def partial_positionals(func, *positionals, **keywords):
def wrapper(*args, **kwargs):
arg = iter(args)
return func(*(*(next(arg) if i is SKIP else i for i in positionals), *arg),
**{**keywords, **kwargs})
return wrapper
so that:
def f(x, y, z):
return x + 2 * y + 3 * z
print(partial_positionals(f, 4, SKIP, 6)(5))
outputs:
32

What is the syntax for the input for a def function with multiple nested functions?

I'm learning Python right now and I am just trying to get to grips with all of the syntax options.
Currently, the only thing that I can't seem to google up is what to do if I for some reason want to define a function which contains multiple other defines.
While I understand what to do if there's only 1 define inside the the larger define (val = f()(3,4) returns 7 if you exclude the second def below), I don't know how to correctly use the function below.
If it's possible, what is the syntax for a def function with an arbitrary amount of defined functions within it?
Code:
def f():
def x(a,b):
return a + b
return x
def y(c,d):
return c + d
return y
val = f()(3,4)(5,6)
print(val)
I expected the above to return either (7,11) or 11. However, it returns 'int object is not callable'
When you write val = f()(3,4)(5,6), you want f to return a function that also returns a function; compare with the simpler multi-line call:
t1 = f()
t2 = t1(3,4)
val = t2(5,6)
The function f defines and returns also has to define and return a function that can be called with 2 arguments. So, as #jonrsharpe said, you need more nesting:
def f():
def x(a, b):
def y(c, d):
return c + d
return y
return x
Now, f() produces the function named x, and f()(3,4) produces the function named y (ignoring its arguments 3 and 4 in the process), and f()(3,4)(5,6) evaluates (ultimately) to 5 + 6.

Python, assign function to variable, change optional argument's value

Is it possible to assign a function to a variable with modified default arguments?
To make it more concrete, I'll give an example.
The following obviously doesn't work in the current form and is only meant to show what I need:
def power(a, pow=2):
ret = 1
for _ in range(pow):
ret *= a
return ret
cube = power(pow=3)
And the result of cube(5) should be 125.
functools.partial to the rescue:
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords. If more arguments are supplied to the call, they are appended to args. If additional keyword arguments are supplied, they extend and override keywords.
from functools import partial
cube = partial(power, pow=3)
Demo:
>>> from functools import partial
>>>
>>> def power(a, pow=2):
... ret = 1
... for _ in range(pow):
... ret *= a
... return ret
...
>>> cube = partial(power, pow=3)
>>>
>>> cube(5)
125
The answer using partial is good, using the standard library, but I think it's worth mentioning that the following approach is equivalent:
def cube(a):
return power(a, pow=3)
Even though this doesn't seem like assignment because there isn't a =, it is doing much the same thing (binding a name to a function object). I think this is often more legible.
In specific there's a special function for exponents:
>>> 2**3
8
But I also solved it with a lambda function, which is a nicer version of a function pointer.
# cube = power(pow=3) # original
cube = lambda x: power(x,3)

How to define a function that output another function?

I want to define a function that takes some arguments as input, and uses them to make another function, then outputs the new function.
For example:
makeIncrease(n) --> return a function that takes an argument, and return (argument + n)
applyIncrease(increaseFn, m) --> will apply increaseFn to argument m
So if I do this: applyIncrease(makeIncrease(n), m) --> will return m+n
How can I do it in python?
You can read about decorators in Python for more on this. For your specific question:
def applyIncrease(increaseFn, m):
return increaseFn(m)
def makeIncrease(n):
def _innerFn(arg):
return arg + n
return _innerFn
applyIncrease accepts a function and argument, and applies the function to the argument.
makeIncrease accepts an argument n.
Let's say n=2 for the sake of an example. makeIncrease(2) returns a function that takes an argument and adds 2 to it.
Although I began _innerFn with an underscore, this is only a convention - the underscore is not required for the decorator to work.
Note also that functions are first class objects in Python, and that makeIncrease returns _innerFn and not _innerFn(). Return functions exactly as you would variables or object references - no parentheses.
Here are your functions in the interpreter. Note that the object reference wrapped_function refers to _innerFn, i.e. the return value of makeIncrease(2)
>>> wrapped_function = makeIncrease(2)
>>> wrapped_function
<function _innerFn at 0x100496758>
>>> total = applyIncrease(wrapped_function, 3)
>>> total
5
class Example:
def result():
def nestedResult(a,b):
multiply = a*b
return multiply
return nestedResult
if __name__ == "__main__":
x = result()
print "multiplication_result:", x(1,10)

Categories

Resources