I am building a function that accepts the list of tuples. For example:
my_list = [
("str1", 1, 11),
("str2", 2, 22),
("str3", 3, 33),
("str4", 4, 44)
]
I want to create a function with definition such that it will ONLY accept the parameters with the size of each nested element as "3". How can I define my function to accept list only of my desired nested length?
Here is the sample code snippet of what I am trying to achieve (I know it is syntactically incorrect):
def newattr_ratio(data, *(name,idx,idy)):
for name,idx,idy in *(name,idx,idy):
data[name]= data[data.columns[idx]]/data[data[columns[idy]]]
How can I create a function with such parameter definition?
You can not restrict that during the declaration of your functional parameter. However you may create a custom decorator to check for the length of your nested tuples as:
from functools import wraps
def check_params(nestedsize=None):
def _check_params(func):
def _decorator(data, *args ):
if nestedsize and all(len(arg)==nestedsize for arg in args):
return func(data, *args)
else:
raise Exception("Invalid args passed with the function call")
return wraps(func)(_decorator)
return _check_params
Above decorator takes the optional parameter nestedsize
to check the size of your nested tuples.
Now, for passing the unpacked version of lists to your function, your function definition should be:
@check_params(nestedsize=3) # <-- added decorator here, with nested size as "3"
def newattr_ratio(data, *args): # <-- note the asterisk sign here
for name, idx, idy in args:
print("{} - {} - {}".format(name, idx, idy))
Sample Run:
# Correct input
>>> my_list = [("a", 1, 11), ("b", 2, 22), ("c", 3, 33)]
# v asterisk again to unpack the list
>>> newattr_ratio([], *my_list)
a - 1 - 11
b - 2 - 22
c - 3 - 33
# Incorrect input, raising custom exception
>>> my_list = [("a", 1, 11, "wrong_data"), ("b", 2, 22), ("c", 3, 33)]
>>> newattr_ratio([], *my_list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in _decorator
Exception: Invalid args passed with the function call
If you do NOT want to unpack the list and pass it as it is, then your function should be:
@check_params(nestedsize=3)
def newattr_ratio(data, args): # <-- No asterisk here
for name, idx, idy in args:
print("{} - {} - {}".format(name, idx, idy))
# ... whatever your logic is
Sample run (same result as above, only difference is in function call):
# correct input
>>> my_list = [("a", 1, 11), ("b", 2, 22), ("c", 3, 33)]
>>> newattr_ratio([], my_list) # <-- No asterisk here
a - 1 - 11
b - 2 - 22
c - 3 - 33
# Incorrect input, raising custom exception
>>> my_list = [("a", 1, 11, "wrong_data"), ("b", 2, 22), ("c", 3, 33)]
>>> newattr_ratio([], my_list) # <-- No asterisk here
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in _decorator
Exception: Invalid args passed with the function call
However if you won't use the decorator, anyway your for loop will raise the exception as ValueError: too many values to unpack
. So you may skip the decorator if you are fine without custom exception
For example:
# v extra value here
>>> my_list = [("a", 1, 11, "wrong_data"), ("b", 2, 22), ("c", 3, 33)]
>>> newattr_ratio([], my_list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in newattr_ratio
ValueError: too many values to unpack