I have a function like this one:
def hexify_string(aString):
#code for string2hexa conversion
...and I want to have a function who accepts one or more (quantity undefined) parameters, and to return the hexadecimal representation of the sum of the parameters.
def hexify(a,b...n):
#map hexify_string to all the parameters, and return the sum of them
Is there a way of doing this using *args / **kwars?
*args takes all non-keyword parameters and turns them into a list. You can map hexify_string to each element of the list, and then return the sum of all the elements in the list.
def hexify(*args);
return sum(map(hexify_string, args)
This is assuming your hexify_string function returns a hex value, not a string.
Is this what you want? Collect any number of arguments, which should all be strings. Pass each string to hexify_string() which returns an integer. Sum the integers and return the sum.
def hexify(*lst):
n = sum(hexify_string(s) for s in lst)
return n
When you want to collect the arguments, you want to treat them all the same, and you don't know how many there will be, that is exactly what the *args syntax was intended for. This is a perfect use case for it.
**kwargs collects name=value arguments, and you don't want any of those here.
Related
I need to pass a large tuple and a single variable into a threaded task as arguments.
excelbtn_text.set("Outputting...")
excelClass = excelCL()
excel_thread = threading.Thread(target=excelClass.excelOut, args=(dcf_data_tuple, excelbtn_text))
excel_thread.daemon = True
excel_thread.start()
However I receive an error, TypeError: excelOut() missing 242 required positional arguments. Is there anyway I can get past this problem?
The error never occurred while I was only passing the tuple as an argument.
First, to pass a tuple and another value, you can just make another tuple with two members—the big tuple, and the other value. Exactly as you're doing:
args=(dcf_data_tuple, excelbtn_text)
But the arguments you pass have to match the method's function definition. Passing a valid tuple of 2 values as the arguments for a method doesn't work unless that method takes 2 parameters.
To resolve your confusion, first, this does not mean what you think it does:
args=(dcf_data_tuple)
Parentheses do not create a tuple; commas create a tuple. In other words, (2) is not a 1-element tuple containing the number 2, it's just the number 2. And (dct_data_tuple) is not a 1-element tuple containing the tuple dct_data_tuple, it's just dct_data_tuple.
So, the function definition for excelClass.excelOut is presumably taking not a single giant tuple as a parameter, but rather hundreds of separate parameters.
This is a bizarre design, but it's not actually illegal.
And that matches the exception you're getting: when you pass it 2 arguments (the first of which is a giant tuple), rather than hundreds arguments, it complains that you're missing 242 positional arguments:
TypeError: excelOut() missing 242 required positional arguments
The simplest way to fix this is to give excelOut a reasonable signature that matches what you want to pass it:
def excelOut(self, data_tuple, text):
# do stuff here
If you for some reason can't change its definition, then you have to look at what the definition is, and try to match it. If, for example, it looks like this:
def excelOut(self, data0, data1, … hundreds more, …, text):
… then you have to call it like this:
args=dcf_data_tuple + (excelbtn_text,)
Notice the comma at the end. That means (excelbtn_text,) is a 1-element tuple. And then we add the giant tuple to the 1-element tuple and get back a giant-plus-1-element tuple, which now matches the method's parameters.
If I understood your problem, you can add an asterisk before your tuple to pass the arguments unwrapped:
excelbtn_text.set("Outputting...")
excelClass = excelCL()
excel_thread = threading.Thread(target=excelClass.excelOut, args=(*dcf_data_tuple, excelbtn_text))
excel_thread.daemon = True
excel_thread.start()
So i have a function which takes multiple values:
def kgV(a,b, *rest):
#the function itself doesnt matter for the question
#beside that it returns an int no matter how many arguments where passed
now i have a list or range():
# for example
myRange = range(2, 10)
myList = [2,9,15]
Now i want it to possible to give my Function the list or range as parameter so that it works as if i had given the every int of the range or list as parameter.
#how can i make this work?
kgV(myRange)
kgV(myList)
i tried some things like: for i in a etc
but they all returned errors :-/
edit: i just solved it using a help function but it seems a very un pythonic way of doing it, so is there a more pythonic / generic way of doing it?
def kgVList(liste):
result = liste[0]
for i in liste:
result = kgV(i, result)
return result
You can simply unpack the values like this:
kgV(*a)
I want to write my own sum function to get the sum of a variable-length argument.
def myadd(*tuple):
sum=0
for element in tuple:
sum=sum+element
return(sum)
call method 1:
myadd(*(1,2,3,4))
It is the most formal way to call the function.no problem here.
call method 2:
myadd(1,2,3,4)
It also can get the result,why?
call method 3:
myadd((1,2,3,4))
error TypeError: unsupported operand type(s) for +: 'int' and 'tuple'.
In my point of view,call 2 and call 3 can not be accepted by python,there are no * operator in the position of arguments?can you tell me the pricinple of the operation on python function ?
You're mixing up variable-argument parameters and argument unpacking. This is a common mistake for beginners, because they both use the same * for syntax, and they're not completely unrelated… but they're not nearly as closely related as you think.
These two calls do the exact same thing:
myadd(*(1,2,3,4))
myadd(1, 2, 3, 4)
What the * means here is "take the following iterable, and unpack it into a bunch of separate arguments.
It doesn't matter whether the function you're calling was defined as f(*args), f(a, b, c, d), or f(a, b, *args), you're passing it 4 arguments.
This means method 1 is not "the most formal way to call the function"; in fact, it's just an obfuscated version of method 2.
This, on the other hand, does not do the same thing:
myadd((1, 2, 3, 4))
That passes a single argument, which happens to be a tuple.
So, your function is defined like this:
def myadd(*tuple):
This means whatever it arguments it's passed, no matter how they're passed (except for keyword arguments, but let's ignore that for the moment), they're going to be tossed into a list named tuple. So, let's look at your three cases.
In the first case, you're passing 4 arguments, all of which are integers. So, tuple gets a list of 4 integers. When you iterate over that list, each member is an integer, so you can add them up with no problem.
In the second case—which, again, is exactly the same—you're passing 4 integers, so tuple gets a list of 4 integers.
In the third case, you're passing 1 argument, which is a tuple, so tuple gets a list of 1 tuple. When you iterate over that list, each member is a tuple, and you can't add that to a number.
For more details, see Arguments and parameters, which has links to all the useful places to look in the docs, and hopefully a readable overview.
You are passing the whole tuple as one argument, and tuples cannot be added to numbers. If you want to pass all the tuple elements as individual arguments, use the * operator:
myadd(*x)
def myadd(x):
sum=0
for element in x:
sum=sum+element
return(sum)
x=(1,2,3)
print myadd(x)
output
6
I'm extracting features from a specific class of objects I have and decided to built a method that extracts all features at once, i.e. call all feature extraction methods and return them in a tuple, as shown below.
def extractFeatures(self):
if self.getLength()<=10:
return ()
else:
return (self.getMean(), # a number
self.getStd(), # a number
self.getSkew(), # a number
self.getKurt(), # a number
# Many other methods here, such as:
self.getACF(), # which returns a TUPLE of numbers...
)
Nevertheless, I have some methods returning tuples with numbers instead of individual numbers, and since I'm still doing some tests and varying the length in each one of these tuples, hard typing self.getACF()[0], self.getACF()[1], self.getACF()[2], ... is not a good idea.
Is there a pythonic way of getting these values already "unpacked" so that I can return a tuple of only numbers instead of numbers and maybe nested tuples of indefinite size?
You could build a list of the values to return, then convert to a tuple at the end. This lets you use append for single values and extend for tuples:
def extractFeatures(self):
if self.getLength() > 10:
out = [self.getMean(), self.getStd(), self.getSkew()]
out.append(self.getKurt()] # single value
out.extend(self.getACF()) # multiple values
return tuple(out)
Note that this will implicitly return None if self.getLength() is 10 or less.
However, bear in mind that your calling function now needs to know exactly what numbers are coming and in what order. An alternative in this case is to return a dictionary:
return {'mean': self.getMean(), ... 'ACF': self.getACF()}
Now the calling function can easily access the features required by key, and you can pass these as keyword arguments to other functions with dictionary unpacking:
def func_uses_mean_and_std(mean=None, std=None, **kwargs):
...
features = instance.extractFeatures()
result = func_uses_mean_and_std(**features)
I'm currently learning Python, and I have problems modifying this function to work as I would like. This is a recursive function that finds gcd from two integers. data is a tuple with two integers. How to modify this recursive function to work with one parameter?
def gcd(data):
a, b = data
if b == 0: return a
return gcd(b, a % b)
If i execute it like this, i get
TypeError: checkio() takes 1 positional argument but 2 were given
If I try to gather arguments by defining def gcd(*data):, I get
ValueError: need more than 1 value to unpack.
Is this possible at all ?
Your function is expecting a single variable (a tuple), but you are passing two variables, try this:
return gcd((b, a % b))
Sure, you just need to be consistent. Either define gcd to take two parameters:
def gcd(a, b):
or wrap the values in a tuple when you call it:
return gcd((b, a % b))
I think you should just be able to put an extra pair of parentheses around your arguments, like so:
return gcd((b, a % b))
This will make your two positional arguments into a tuple passed as a single positional argument.
Alternatively you could drop the unpacking and just accept two positional arguments instead of a single tuple in the first place.
Passing a literal tuple as a parameter requires another set of parentheses to make clear that it is not 2 separate parameters:
return gcd((b, a % b))
Alternatively, the tuple could be assigned to a separate name first (with or without parentheses):
next_data = b, a % b
return gcd(next_data)
gcd(*data) would work, but you would also need to change your initial call to pass individual parameters as well, in the form of either gcd(a, b) or gcd(*data).