call a function with optional and name arguments in another function - python

How can we do function implementation for the following?
For optional and named arguments we write function in following way.
def funct(*args, **kwargs):
for arg in args:
print “arg =”, arg
for key in kwargs.keys():
print “arg[{0}]={1}”.format(key, kwargs[key])
If I want to call this function inside another function of same protocol, how can I implement?
def funct2(*args, **kwargs):
# call funct() above
funct(????????)
So is there any way to call the first funct() with optional arguments inside the new funct2() with the same type of optional arguments?

The syntax for calling a function is basically the same as when defining the function. So your funct2 would look like:
def funct2(*args, **kwargs):
# call funct() above
funct(*args, **kwargs)
Here are the Python docs covering the subject: https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists

Related

Call Python function passed as parameter without knowing if it takes any parameters

I have a project in which I need to do some things, call one of a few functions, and then do some other things:
def doCommand(function, parameter_for_function):
# do a thing
function(parameter_for_function)
# do a thing
My problem is that I don't know if the function I will be passing will require a parameter of its own!
How can I allow my function to call both functions that have no parameters, and functions that have one?
The preferred method of handling this is probably along these lines:
def doCommand(function, *args, **kwargs):
# do a thing
function(*args, **kwargs)
# do a thing
*args and **kwargs allow arbitrary arguments to be passed along to a method. As the name implies, these allow you to call doCommand with an arbitrary number of arguments and keyword arguments as well that get passed onto function.
I suggest explicitly saying that the function you take is one that's called with no parameters:
from typing import Callable
def doCommand(function: Callable[[], None]) -> None:
# do a thing
function()
# do a thing
If the function needs parameters, it's then explicitly the responsibility of the doCommand caller to provide them, e.g. within a lambda expression:
def foo(param) -> None:
print("foo: ", param)
doCommand(lambda: foo("bar"))
or a named wrapper function:
def foobar() -> None:
foo("bar")
doCommand(foobar)

How to dynamically generate a list of functions with a decorator

I have a series of functions in a module, for example
def some_func1(param1, param2): pass
def another_func(param1, param2): pass
I would like the easiest way to add them to the list of called functions and then call some of them at a certain point by filter, with parameters. I tried to add to a list of functions using a decorator, something like this:
all_func = {}
def decorator(filter):
def function_decorator(func):
def wrapped(*args, **kwargs):
return func(*args, **kwargs)
return wrapped
all_func[filter] = function_decorator
return function_decorator
#decorator(filter='1')
def some_func1(param1, param2): pass
#decorator(filter='2')
def another_func(param1, param2): pass
#decorator(filter='3')
def another_big_func(param1, *arg): pass
and then when using a loop using a filter, call the functions that match the filter:
arg1 = some_obj
arg2 = another_obj
for i in range(3, 4):
func = all_func.get(i)
func(arg1, arg2)
That is, when adding a function, I simply prescribe a new filter value, not caring that I need to register something else somewhere, and then I call them on this filter
But something went wrong, at the time of all_func.get (i) I get a function_decorator, not a function, and I don’t understand how to call it with the given parameters.
I haven’t worked with decorators before, maybe I somehow misunderstood the concept.
You registered the decorator, not the wrapper. Note that what you named decorator() is really a decorator factory, calling decorator(...) produces the decorator function function_decorator(). Python then calls the function_decorator() function to do the actual decorating task, and its return value is used to replace the decorated function. You want to register the result of that process, not function_decorator itself.
Register the wrapper, wrapped(), instead:
def decorator(filter):
def function_decorator(func):
def wrapped(*args, **kwargs):
return func(*args, **kwargs)
all_func[filter] = wrapped
return wrapped
return function_decorator
Now all_func.get(i) will return one of the wrapped() functions. Calling wrapped() then calls the decorated function, via the func reference.
Your wrapper() is really a no-op, so can be omitted. Decorators don't have to return a replacement function, the original function can be returned unchanged. Use the func reference to add to your registry:
def decorator(filter):
def function_decorator(func):
all_func[filter] = func
return func
return function_decorator
Note that you don't have a list, you have a dictionary, a mapping from key to value. Not that matters to the problem.
Slightly unrelated (cf Martijn's answer for the core issue), but:
1/ all_funcs is a dict, not a list
2/ if you're using strings as keys when populating your dict (#decorator(filter='1'), you have to use strings as keys too to get your functions back (range() yields ints, not strings), so you want
for key in map(str, range(3, 4)):
func = all_funcs.get(key)

How can I send unknown list of arguments to a python decorator?

I have created a python decorator as shown below. I want this decorator to accept an unknown list of arguments. But the code below doesn't work.
#!/usr/bin/env python
from functools import wraps
def my_decorator(decorated_function, **kwargs):
print "kwargs = {}".format(kwargs)
#wraps(decorated_function)
def inner_function(*args, **kwargs):
print "Hello world"
return decorated_function(*args, **kwargs)
return inner_function
#my_decorator(arg_1="Yolo", arg2="Bolo")
def my_func():
print "Woo Hoo!"
my_func()
When I run it, I get this error:
File "./decorator_test.py", line 14, in <module>
#my_decorator(arg_1="Yolo", arg2="Bolo")
TypeError: my_decorator() takes exactly 1 argument (0 given)
Why is the **kwargs not accepting the multiple arguments I'm sending into the decorator? How can I fix it?
Essentially, when you have a decorator that accepts arguments, you're kind of calling it twice, once with the keyword arguments, and then again with just the function to be decorated.
Before the #deco syntax, you would decorate a function just by passing it into the decorator function
func = deco(func)
And if you wanted to include other keyword arguments, you could just pass them in at the same time
func = deco(func, arg=True, arg2=5)
But the #deco syntax doesn't allow that, it works more like this, so you're calling a function returned by the decorator function.
func = deco(arg=True, arg2=5)(func)
To do this with the #deco syntax, you would create a decorator that tests to see whether it was called with just a function (the decoration part), or whether it was called with keyword arguments (which sets up the decorator to be passed a function).
def deco_with_kwargs(func=None, **kwargs):
def deco(func_):
def wrapped_func(*fargs, **fkwargs):
print kwargs
return func_(*fargs, **fkwargs)
return wrapped_func
if func:
return deco(func)
else:
return deco
You could use it like this without any keyword arguments.
#deco_with_args
def my_func():
return 1
Or you could call it like this with keyword arguments. In this case, you're actually calling the decorator function, which returns another decorator function, which is then called to actually decorate the function.
#deco_with_args(test=True)
def my_func():
return 1

passing functions as argument with named parameters

I followed this to pass functions as arguments:
Passing functions with arguments to another function in Python?
However, I could not figure out how to pass function with its own arguments as names parameters
def retry(func, *args):
func(*args)
def action(args):
do something
retry(action, arg1, namedArg=arg2)
Here I get an exception:
TypeError: retry() got an unexpected keyword argument 'namedArg'
Normally, I can do:
action(arg1, namedArg=arg2)
Please help/
*args and it's sibling **kwargs are the names generally used for extra arguments and key word arguments. You are passing a kew word argument when you pass namedArg=arg2.
So, try this instead:
def retry(func, *args, **kwargs):
func(*args, **kwargs)
def action(*args, **kwargs):
do something
retry(action, arg1, namedArg=arg2)
If you instead use
def action(args, kwargs):
do something
Then you will end up with args as a list of arguments and kwargs as a dictionary of key word arguments, so in your case
args = [arg1]
kwargs = {'namedArg':arg2}
Read this, keyword arguments in python doc.
As the error clearly states that got an unexpected keyword argument 'namedArg'. where as you are providing only arguments in *args.
You will find plenty of examples to understand keyword arguments.
What you need is functools.
http://docs.python.org/2/library/functools.html#functools.partial
from functools import partial
def action(arg):
do something
def action2(arg=1):
do something
def action3(arg1, arg2=2):
do something
partial(action, arg1)
partial(action, arg1, arg2=3)

In Python, is it possible to decorate both a class and non-class method with the same decorator?

I have a simple exception-logging decorator, which is handy for sending myself emails when my scripts throw exceptions.
def logExceptions(func):
def wrapper():
try:
func()
except Exception, e:
logger.exception(e)
return wrapper
However, if I want to decorate a class method, I have to modify wrapper() to take a 'self', otherwise I get the following error:
TypeError: wrapper() takes no arguments (1 given)
Of course, at that point I can't use it to decorate any non-class methods, because then this error occurs:
TypeError: wrapper() takes exactly 1 argument (0 given)
Is there a clean way to tackle this problem? Thank you =)
The usual thing is to define your wrapper so it accepts *args and **kwargs and passes them on to the function it wraps. This way it can wrap any function.
Also, I get the impression that what you are calling a "class method" is what Python calls an "instance method", and what you call "non-class method" is what Python calls a "function". A "non-class method" (e.g., instance method) in Python takes a self argument.
Difference between instance method, classmethod and staticmethod
First a note: both static method and class method are also functions, so standard function rules mostly apply to them. I understand your question is about the difference between static method (which has no extra arguments passed) and class method (which receives class in the first argument):
class Test(object):
def standard_method(*args, **kwargs):
# it is instance method (first argument will be instance)
return args, kwargs
#classmethod
def class_method(*args, **kwargs):
# it is class method (first argument will be class)
return args, kwargs
#staticmethod
def static_method(*args, **kwargs):
# it is static method (receives only arguments passed explicitly)
return args, kwargs
The proof (or rather self-explanatory example) is here:
>>> t = Test()
>>> t.standard_method()
((<__main__.Test object at 0x0000000002B47CC0>,), {})
>>> t.class_method()
((<class '__main__.Test'>,), {})
>>> t.static_method()
((), {})
As you see, the list of arguments passed differs depending on which type of method you choose. The problem you are facing is variable number of arguments.
Solution
There is a solution for that - use argument unpacking:
def some_decorator(func):
def wrapper(*args, **kwargs):
# do something here
# args is a tuple with positional args, kwargs is dict with keyword args
return func(*args, **kwargs)
return wrapper
After that, function returned by some_decorator will accept the same amount of arguments as decorated function.
So both these examples will work:
#some_decorator
def say_hello():
print 'hello'
#some_decorator
def say_something(something):
print something
Appendix
To give you fully complete example, it would be good if you would use such constructions (note usage of functools.wraps):
from functools import wraps
def some_decorator(func):
#wraps(func)
def wrapper(*args, **kwargs):
# do something here
# args is a tuple with positional args, kwargs is dict with keyword args
return func(*args, **kwargs)
return wrapper
The reason for that is listed in documentation for functools.wraps(): it preserves function name and docstring, effectively resulting in the wrapper looking like a wrapped function (which is useful sometimes).
An alternative to decorating is use sys.excepthook which is a callback that operates on all uncaught exceptions to which you can assign your custom logging function. The benefit is that then you dont need to mutilate (and more importantly, keep track of) every function that you are interested in logging exceptions for.

Categories