I have a function that takes in two list values and returns the AND operator output of them. Now I need to make the function take multiple values and get the output. I have done this for now for two lists of flag values:
def and_op(lst1, lst2):
return np.array([(lst1 & lst2) for lst1,lst2 in zip(lst1, lst2)])
and_op([0,0,1,1,0], [1,0,1,1,1])
OUTPUT:
array([0,0,1,1,0])
I now need to change this function such that the arguments are dynamically given and the number of arguments can be more than two.
and_op([0,1,1,0], [1,1,0,1], [1,1,1,0], [0,1,0,1])
How can I change the function so I can get output for the case above? I thought of *args, but got super confused on how to use & operator on it.
Use all function and iterate your args.
def and_op(*args):
return np.array([int(all([arg[i] for arg in args])) for i in range(len(args[0]))])
Related
Hope you're all well with the caotic world we're living...
This might be a very beginner level question, but I'd like to understand why It is like that.
Let's say I have a list of complex:
myList = [(1.231 +2.254j), (2.875 +23.543j), ...]
I've been trying to round the values with this function:
def round_complex(x, digits):
return complex(round(x.real, digits), round(x.imag, digits))
And for doing so, I've tried this:
for item in myList:
item = round_complex(item, 2)
Expecting that myList values get changed, for example:
myList = [(1.23 +2.25j), (2.88 +23.54j), ...]
But, It does not work.
I've also tried with a more simple example, like a list of floats and the base round function from python. It also does not work.
Is there a way for me to change a value of an iterable object with this kind of for loop (for-in)?
Or do I really have to do this:
for i in range(len(myList)):
myList[i] = round_complex(myList[i], 2)
The simple answer is: NO.
Python uses a mechanism, which is known as "Call-by-Object", sometimes also called "Call by Object Reference" or "Call by Sharing" when pass function parameters.
If you pass immutable arguments like integers, strings or tuples to a function, the passing acts like call-by-value. The object reference is passed to the function parameters. They can't be changed within the function, because they can't be changed at all, i.e. they are immutable. It's different, if we pass mutable arguments. They are also passed by object reference, but they can be changed in place within the function.
So, after your iterate the list, the value (1.231 +2.254j) would be a immutable argument which your change won't affect the outside variable. But if you pass the value like [1.231 +2.254j] to function, then it will make effect like next:
test.py:
myList2 = [[(1.231 +2.254j)], [(2.875 +23.543j)]]
print(myList2)
def round_complex(x, digits):
return complex(round(x.real, digits), round(x.imag, digits))
for item2 in myList2:
item2[0] = round_complex(item2[0], 2)
print(myList2)
Execution:
$ python3 test.py
[[(1.231+2.254j)], [(2.875+23.543j)]]
[[(1.23+2.25j)], [(2.88+23.54j)]]
In a word, for you scenario, if you insist organize your input data as that & iterate with that way, you can't change the outside value directly inside the function.
You may refers to this to learn more.
The thing I understand by reading for question that you want to Assign the values of i in myList. For doing so you can use append i.e
for i in mylist:
mylist.append(round_complex(i, 2))
I wondering how i would enter multiple variables into my function:
def Dot_Product(Vector1,Vector2):
return sum([x*y for x,y in zip(Vector1,Vector2)])
print Dot_Product([1,2,1],[1,1,1])
I have looked into *args and **kwargs but I'm not sure how I would implement this so that the list comprehension would also iterate over an unknown number of variables. I'm not sure if its possible so if there are any alternatives, they would be greatly appreciated.
I understand how *args and **kwargs work however I'm unsure how to implement a list comprehension that would iterate over an unknown number of variables as in the example given i can only iterate over x,y or x,y,z or n number of lists lists at any one as long as I know what number n is. Since i don't know n how can i change the list comprehension to handle that?
You can try this approach:
multiplication = lambda x,y: x*y
def dot_product(*args):
return sum([reduce(multiplication, arg) for arg in zip(*args)])
And then you can pass as many arguments as you want:
In [5]: print dot_product([1,2,1], [1,1,1])
4
In [6]: print dot_product([1,2,1], [1,1,1], [1,1,1])
4
You can check the reduce function here
I think you will also need to validate that all of the items are lists and they have the same length.
Also, as a suggestion by #PauloAlmeida the multiplication variable is not needed as the standard library provides it to us, we can import it like this:
from operator import mul
and then we can use mul instead of multiplication variables which represents the lambda function used on the reduce function.
I pass a list to a method which accepts multiple params (*values). If I pass multiple values separated by "," its all fine, but if I pass a list *values turns into a tuple and doesnt iterate the values and the only element is the list I would like to iterate. Can somebody explains that? Is there some way to work around that, that both ways work?
My method:
def accept(*values):
for value in values:
#do something with value
Works:
foo.accept(value1, value2, value3)
Doesnt work:
values = [value1, value2, value3]
foo.accept(values)
Thank you for any help
You need to unpack the list in the function call with the * operator:
foo.accept(*values)
How the multiple parameters feature in python works is that you can pass in a variable number of arguments to the function, and it will automatically turn them into a list (so you don't have to manually) and then execute the code in the function. So when you do foo.accept(value1, value2, value3), it creates a list [value1, value2, value3] and labels this list as the argument to your function, and then you code iterates through the list. However, when you do
values = [value1, value2, value3]
foo.accept(values)
the variable arguments (varargs) feature will wrap your values list into another list so now the argument to your function is [[value1, value2, value3]] and when your for loop does the iteration, it only goes through the one element in this bigger list (the one element being your values list).
Hope this helps!
This syntax is explicitly for taking an arbitrary number of arguments a input
def accept1(*values):
#do something with values
For any given number of arguments it's exactly the same as writing, e.g.:
def accept2(arg1, arg2, arg3):
values = (arg1, arg2, arg3)
#do something with values
To call a function with 3 arguments you can write for both as usual:
accept1(1,2,3)
accept2(1,2,3)
But if you have the arguements in a list or tuple you could do
args = (1,2,3)
accept1(args[0], args[1], args[3])
accept2(args[0], args[1], args[3])
This of course is inflexible and a lot to write so python has a shortcut that again works for an arbitrary number of arguments:
accept1(*args)
accept2(*args)
So in both cases that * denotes a generic way to handle multiple parameters by either
packing individual arguments of a function into a list (in def), or
unpacking a list into individual arguments of a function.
From the Python 2.7.10 documents (slight edit):
4.7.3. Arbitrary Argument Lists
Finally, the least frequently used option is to specify that a function can be called with an arbitrary number of arguments, i.e. using *args. These arguments will be wrapped up in a tuple.
Another point that might help in our understanding is that in Python the parenthesis are redundant in the following line of code:
a = (1, 2, 3)
It would have been enough to write:
a = 1, 2, 3
So onto answering the question. When you have foo.accept(1, 2, 3) the variable arguments get wrapped into a tuple. To verify this step through the code using your favorite debugger into accept() and find that there the arguments have indeed been wrapped in a tuple:
values = (1, 2, 3)
This is what is expected by definition, and the iteration goes over the three elements of the tuple 1, 2, and 3.
On the other hand when you call foo.accept([1, 2, 3]), again, by definition the argument gets wrapped in a tuple. To verify this step through the code into accept() and find:
values = ([1, 2, 3])
This might be unexpected, but it is the way *args are passed. Now the iteration goes over the one element in the tuple [1, 2, 3].
A workaround is usually specific with what is trying to be achieved. But perhaps something as simple as:
foo.accept(1, 2, 3)
or:
foo.accept(*[1, 2, 3])
I created a function that takes an arbitrary number of variables via the *args feature. Now another function needs to call this original function using a list of varying length, but I can't seem to find a solution. As a simplified example:
def print_all(*args):
for x in args:
print(x)
print_all([1,2,3,4,5])
Running this, the console displays:
[1,2,3,4,5]
But I would like it to display:
1
2
3
4
5
Is there a way to turn an iterable like this into proper input for a function that accepts *args like above?
The following will do the trick:
print_all(*[1,2,3,4,5])
With the star operator every item in the list is like been passed as a separate argument to the function.
Remove the * which exists in the parameter part of the function definition. Here * is unnecessary.
def print_all(args):
for x in args:
print(x)
I have a list a = [1,2,3,4,5]. And I have a function, say, Func(x). I know that if I do Func(a) then the reference of a will be passed into Func(x). And if I do Func(a[:]), a new list will be created and passed into Func(x).
So my question is: Is it possible to only pass the first three elements into Func(x) by reference, like Func(a) (I don't want to pass the whole list a into function due to certain reason)? If I do Func(a[:4]) a new list will be created and that's what I want to avoid.
The only way I can think about is to pass a and the indexes into Func(x), like Func(a, start, end).
There is no way to create a 'window' on a list, no.
Your only options are to create a slice, or to pass in start and end indices to the function and have the function honour those.
The latter is what the bisect module functions do for example; each function takes a lo and hi parameter that default to 0 and len(list) respectively:
def func(lst, lo=0, hi=None):
if hi is None:
hi = len(lst)
Why not create a second argument so that Func (a) becomes Func (a, n) where a is the reference to your array and n is the position in the array to which you want to evaluate to?
Something like:
Func (a, 2)
With that example the first three elements are evaluated.