This was the program for our test and I couldn't understand what is going on. This problem is called nested function problem.
def foo(a):
def bar(b):
def foobar(c):
return a + b + c
return foobar
return bar
a, b, c = map(int,input().split())
res = foo(a)(b)(c)
print(res)
I have tried to debug this program but couldn't get any idea about why it is working.
Why is foo(a)(b)(c) not giving an error?
Why it is working and what it is called?
This is a closures concept, Inner functions are able to access variables of the enclosing scope.
If we do not access any variables from the enclosing scope, they are just ordinary functions with a different scope
def get_add(x):
def add(y):
return x + y
return add
add_function = get_add(10)
print(add_function(5)) # result is 15
Everything in Python is an object, and functions as well, so you can pass them as arguments, return them, for example:
def inc(var):
return var + 1
def my_func():
return inc
my_inc = my_func()
print(my_inc) # <function inc at ...>
print(my_inc(1)) # 2
Moreover it's closed to decorator's concept:
def log_this(func):
def wrapper(*args, **kwargs):
print('start', str(args))
res = func(*args, **kwargs)
return res
return wrapper
#log_this
def inc(var):
return var + 1
print(inc(10))
I need to write a function that satisfies this test in pytest:
def test_return_logger(capsys):
#return_logger
def myfunc(a, b, c):
return a + b + c
val = myfunc(4, 5, 6)
out, err = capsys.readouterr()
assert val == 15
assert "Function returned: 15" in out
Here is what I currently have and it is not working:
def return_logger(f):
def newfunc(s):
original_return_value = f(s)
return f"Function returned: {original_return_value}"
return newfunc
Im honestly completely lost!
Your test wants the function to return the value, and print the string that you were returning.
The newfunc(*args) also solves passing in multiple arguments - they are automatically unpacked when calling the second function.
You probably want this:
def return_logger(f):
def newfunc(*args):
original_return_value = f(*args)
print(f"Function returned: {original_return_value}", sys.stderr)
return original_return_value
return newfunc
Now, when you call the decorated function, it will print Function returned: 15 to stderr and return original_return_value.
I want to call a module function with getattr (or maybe something else?) from a string like this:
import bar
funcStr = "myFunc(\"strParam\", 123, bar.myenum.val1, kwarg1=\"someString\", kwarg2=456, kwarg3=bar.myenum.val2)"
[function, args, kwargs] = someParsingFunction(funcStr)
# call module function
getattr(bar, function)(*args, **kwargs)
How can I extract the args and kwargs from the string, so I can pass them to getattr?
I tried a literal_eval approach with pythons ast module. But ast is not able to evaluate the enums of the module bar. And all other examples on SO pass a kwargs map with only strings in it. And they especially never parse the arguments from a string. Or is there another way to directly call the function from the string?
EDIT: A python script reads the function string from file. So using eval here is not advised.
EDIT2: Using python 3.6.3
EDIT3: Thanks to the first two answers I came up with two ideas. After parsing the args and kwargs out of the input string there are two possibilities for getting the right type of the arguments.
We could use ast.literal_eval(<value of the argument>). For arguments with standard type like in kwarg2 it will return the needed value. If this excepts, which will happen for the enums, then we we will use getattr on the bar module and get the enums. If this excepts as well, then the string is not valid.
We could use the inspect module and iterate through the parameters of myFunc. Then for every arg and kwarg we will check if the value is an instance of a myFunc parameter (type). If so, we will cast the arg/kwarg to the myFunc parameter type. Otherwise we raise an exception because the given arg/kwarg is not an instance of a myFunc parameter. This solution is more flexible than the first one.
Both solutions feel more like a workaround. First tests seem to work. I will post my results later here.
Does this help?
funcStr = r"""myFunc(\"strParam\", 123, bar.myenum.val1, kwarg1=\"someString\", kwarg2=456, kwarg3=bar.myenum.val2)"""
def someParsingFunction(s):
func, s1 = s.split('(', 1)
l = s1.replace('\\','').strip(')').split(', ')
arg_ = [x.strip('"') for x in l if '=' not in x]
kwarg_ = {x.split('=')[0]:x.split('=')[-1] for x in l if '=' in x}
return func, arg_, kwarg_
class bar:
def myFunc(self, *args, **kwargs):
print(*args)
print(kwargs)
[function, args, kwargs] = someParsingFunction(funcStr)
getattr(bar, function)(*args, **kwargs)
# 123 bar.myenum.val1
# {'kwarg1': '"someString"', 'kwarg2': '456', 'kwarg3': 'bar.myenum.val2'}
Alternatively
funcStr = r"""myFunc(\"strParam\", 123, bar.val1, kwarg1=\"someString\", kwarg2=456, kwarg3=bar.val2)"""
def someParsingFunction(s):
func, s1 = s.split('(', 1)
l = s1.replace('\\','').strip(')').split(', ')
arg_ = [x.strip('"') for x in l if '=' not in x]
kwarg_ = {x.split('=')[0]:x.split('=')[-1] for x in l if '=' in x}
return func, arg_, kwarg_
class Bar:
def __init__(self):
self.val1 = '111'
[function, args, kwargs] = someParsingFunction(funcStr)
bar = Bar()
obj_name = 'bar' + '.'
args = [bar.__getattribute__(x.split(obj_name)[-1]) if x.startswith(obj_name) else x for x in args]
print(args)
def get_bar_args(arg_str):
"""
example:
arg_str='bar.abc.def'
assumess 'bar' module is imported
"""
from functools import reduce
reduce(getattr, arg_str.split('.')[1:], bar)
def parseFuncString(func_str):
'''
example: func_str = "myFunc(\"strParam\", 123, bar.myenum.val1, kwarg1=\"someString\", kwarg2=456, kwarg3=bar.myenum.val2)"
'''
import re
all_args_str = re.search("(.*)\((.*)\)", func_str)
all_args = all_args_str.group(2).split(',')
all_args = [x.strip() for x in all_args]
kwargs = {kw.group(1): kw.group(2) for x in all_args if (kw:=re.search('(^\w+)=(.*)$', x))}
pargs = [x for x in all_args if not re.search('(^\w+)=(.*)$', x)]
pargs = [get_bar_args(x) if x.startswith('bar.') else x for x in pargs]
kwargs = {k: get_bar_args(v) if v.startswith('bar.') else v for k, v in kwargs.items()}
print(f'{all_args=}\n{kwargs=}\n{pargs=}')
func_name = func_str.split("(")[0]
return func_name, pargs, kwargs
In the following example I'm trying to pass arguments to a function that itself has been passed as a kwarg. I have not been successful in passing arguments to the function 'func' from within the class 'TestClass' in the following example:
import sys, threading; from threading import Thread
def func(kwargs):
print('IN:', sys._getframe(0).f_code.co_name)
for key, value in kwargs.items() :
print ('KEY:', key, ', VAL:', value, sep='')
class TestClass(Thread):
def __init__(self, name = sys._getframe(0).f_code.co_name, kwargs = None):
Thread.__init__(self)
self.name = name
self.kwargs = kwargs
print('IN:', self.name)
def run(self):
func = self.kwargs['func']
func_kwargs_inner = {'arg_1': 'INNER-1', 'arg_2': 'INNER-2'}
func() # how to pass func_kwargs_inner to func?
def main():
func_kwargs = {'arg_1': 'OUTER-1', 'arg_2': 'OUTER-2'} # these get passed
# func_kwargs = {} # func_kwargs never gets populated
kwargs = {'func': (lambda: func(func_kwargs))}
test = TestClass(name='my-test', kwargs=kwargs)
test.start()
print('PROGRAM END')
if __name__ == '__main__':
main()
If I try to pass 'func_kwargs_inner' to 'func()', I get syntax errors; if I leave the argument list empty - as in the example - the result is:
IN: my-test
IN: func
KEY:arg_1, VAL:OUTER-1
KEY:arg_2, VAL:OUTER-2
PROGRAM END
whereas the required output once I find a way to pass the arguments correctly is:
IN: my-test
IN: func
KEY:arg_1, VAL:INNER-1
KEY:arg_2, VAL:INNER-2
PROGRAM END
How do I pass 'func_kwargs_inner' to 'func()'?
It seems that if you do the obvious thing, then it will work, and that your code at present explicitly avoids passing the arguments that you want. Specifically, in your TestClass.run you are not passing any arguments to func but instead relies on function arguments that are hard-coded into the lambda expression. So change your line:
func() # how to pass func_kwargs_inner to func?
to pass the arguments:
func(func_kwargs_inner)
Then in main, instead of that lambda expression:
kwargs = {'func': (lambda: func(func_kwargs))}
simply pass the function object itself:
kwargs = {'func': func}
Then you get the expected output:
IN: my-test
IN: func
PROGRAM END
KEY:arg_1, VAL:INNER-1
KEY:arg_2, VAL:INNER-2
I would like to define some generic decorators to check arguments before calling some functions.
Something like:
#checkArguments(types = ['int', 'float'])
def myFunction(thisVarIsAnInt, thisVarIsAFloat)
''' Here my code '''
pass
Side notes:
Type checking is just here to show an example
I'm using Python 2.7 but Python 3.0 whould be interesting too
EDIT 2021: funny that type checking did not go antipythonic in the long run with type hinting and mypy.
From the Decorators for Functions and Methods:
Python 2
def accepts(*types):
def check_accepts(f):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_accepts
Python 3
In Python 3 func_code has changed to __code__ and func_name has changed to __name__.
def accepts(*types):
def check_accepts(f):
assert len(types) == f.__code__.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.__name__ = f.__name__
return new_f
return check_accepts
Usage:
#accepts(int, (int,float))
def func(arg1, arg2):
return arg1 * arg2
func(3, 2) # -> 6
func('3', 2) # -> AssertionError: arg '3' does not match <type 'int'>
arg2 can be either int or float
On Python 3.3, you can use function annotations and inspect:
import inspect
def validate(f):
def wrapper(*args):
fname = f.__name__
fsig = inspect.signature(f)
vars = ', '.join('{}={}'.format(*pair) for pair in zip(fsig.parameters, args))
params={k:v for k,v in zip(fsig.parameters, args)}
print('wrapped call to {}({})'.format(fname, params))
for k, v in fsig.parameters.items():
p=params[k]
msg='call to {}({}): {} failed {})'.format(fname, vars, k, v.annotation.__name__)
assert v.annotation(params[k]), msg
ret = f(*args)
print(' returning {} with annotation: "{}"'.format(ret, fsig.return_annotation))
return ret
return wrapper
#validate
def xXy(x: lambda _x: 10<_x<100, y: lambda _y: isinstance(_y,float)) -> ('x times y','in X and Y units'):
return x*y
xy = xXy(10,3)
print(xy)
If there is a validation error, prints:
AssertionError: call to xXy(x=12, y=3): y failed <lambda>)
If there is not a validation error, prints:
wrapped call to xXy({'y': 3.0, 'x': 12})
returning 36.0 with annotation: "('x times y', 'in X and Y units')"
You can use a function rather than a lambda to get a name in the assertion failure.
As you certainly know, it's not pythonic to reject an argument only based on its type.
Pythonic approach is rather "try to deal with it first"
That's why I would rather do a decorator to convert the arguments
def enforce(*types):
def decorator(f):
def new_f(*args, **kwds):
#we need to convert args into something mutable
newargs = []
for (a, t) in zip(args, types):
newargs.append( t(a)) #feel free to have more elaborated convertion
return f(*newargs, **kwds)
return new_f
return decorator
This way, your function is fed with the type you expect
But if the parameter can quack like a float, it is accepted
#enforce(int, float)
def func(arg1, arg2):
return arg1 * arg2
print (func(3, 2)) # -> 6.0
print (func('3', 2)) # -> 6.0
print (func('three', 2)) # -> ValueError: invalid literal for int() with base 10: 'three'
I use this trick (with proper conversion method) to deal with vectors.
Many methods I write expect MyVector class as it has plenty of functionalities; but sometime you just want to write
transpose ((2,4))
The package typeguard provides a decorator for this, it reads the type information from type annotations, it requires Python >=3.5.2 though. I think the resulting code is quite nice.
#typeguard.typechecked
def my_function(this_var_is_an_int: int, this_var_is_a_float: float)
''' Here my code '''
pass
To enforce string arguments to a parser that would throw cryptic errors when provided with non-string input, I wrote the following, which tries to avoid allocation and function calls:
from functools import wraps
def argtype(**decls):
"""Decorator to check argument types.
Usage:
#argtype(name=str, text=str)
def parse_rule(name, text): ...
"""
def decorator(func):
code = func.func_code
fname = func.func_name
names = code.co_varnames[:code.co_argcount]
#wraps(func)
def decorated(*args,**kwargs):
for argname, argtype in decls.iteritems():
try:
argval = args[names.index(argname)]
except ValueError:
argval = kwargs.get(argname)
if argval is None:
raise TypeError("%s(...): arg '%s' is null"
% (fname, argname))
if not isinstance(argval, argtype):
raise TypeError("%s(...): arg '%s': type is %s, must be %s"
% (fname, argname, type(argval), argtype))
return func(*args,**kwargs)
return decorated
return decorator
I have a slightly improved version of #jbouwmans sollution, using python decorator module, which makes the decorator fully transparent and keeps not only signature but also docstrings in place and might be the most elegant way of using decorators
from decorator import decorator
def check_args(**decls):
"""Decorator to check argument types.
Usage:
#check_args(name=str, text=str)
def parse_rule(name, text): ...
"""
#decorator
def wrapper(func, *args, **kwargs):
code = func.func_code
fname = func.func_name
names = code.co_varnames[:code.co_argcount]
for argname, argtype in decls.iteritems():
try:
argval = args[names.index(argname)]
except IndexError:
argval = kwargs.get(argname)
if argval is None:
raise TypeError("%s(...): arg '%s' is null"
% (fname, argname))
if not isinstance(argval, argtype):
raise TypeError("%s(...): arg '%s': type is %s, must be %s"
% (fname, argname, type(argval), argtype))
return func(*args, **kwargs)
return wrapper
I think the Python 3.5 answer to this question is beartype. As explained in this post it comes with handy features. Your code would then look like this
from beartype import beartype
#beartype
def sprint(s: str) -> None:
print(s)
and results in
>>> sprint("s")
s
>>> sprint(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 13, in func_beartyped
TypeError: sprint() parameter s=3 not of <class 'str'>
All of these posts seem out of date - pint now provides this functionality built in. See here. Copied here for posterity:
Checking dimensionality When you want pint quantities to be used as
inputs to your functions, pint provides a wrapper to ensure units are
of correct type - or more precisely, they match the expected
dimensionality of the physical quantity.
Similar to wraps(), you can pass None to skip checking of some
parameters, but the return parameter type is not checked.
>>> mypp = ureg.check('[length]')(pendulum_period)
In the decorator format:
>>> #ureg.check('[length]')
... def pendulum_period(length):
... return 2*math.pi*math.sqrt(length/G)
you could try with the pydantic validation_decorator. from the documentation pydantic:
Data validation and settings management using python type annotations.
pydantic enforces type hints at runtime, and provides user friendly
errors when data is invalid.
In benchmarks pydantic is faster than all other tested libraries.
from pydantic import validate_arguments, ValidationError
#validate_arguments
def repeat(s: str, count: int, *, separator: bytes = b'') -> bytes:
b = s.encode()
return separator.join(b for _ in range(count))
a = repeat('hello', 3)
print(a)
#> b'hellohellohello'
b = repeat('x', '4', separator=' ')
print(b)
#> b'x x x x'
try:
c = repeat('hello', 'wrong')
except ValidationError as exc:
print(exc)
"""
1 validation error for Repeat
count
value is not a valid integer (type=type_error.integer)
"""
For me, the codes shared above looks complicated. What I did for defining 'generic decorator' for type-check:
I used *args, **kwargs feature, little extra work when using function/method but easy to manage.
Appropriate example definition for test
argument_types = {
'name':str,
'count':int,
'value':float
}
Decoration Defination
//from functools import wraps
def azure_type(func):
#wraps(func)
def type_decorator(*args, **kwargs):
for key, value in kwargs.items():
if key in argument_types:
if type(value) != argument_types[key]:
#enter code here
return 'Error Message or what ever you like to do'
return func(*args, **kwargs)
return type_decorator
Simple sample in code
// all other definitions
#azure_type
def stt(name:str, value:float)->(int):
#some calculation and creation of int output
count_output = #something int
return count_output
// call the function:
stt(name='ati', value=32.90) #can test from that