What is the most pythonic form to define two ways of iterating. In example, I have this original code:
def f1(cat_gen):
for (a, b), c in cat_gen:
if some condition:
yield (a, b), c
but, depending on cat_gen I would need to iterate in this way:
def f1(cat_gen):
for a, b, c in cat_gen:
if some condition:
yield a, b, c
Is there a way to change conditionally just (a, b), c to a, b, c in the for statement
Pass a function that will evaluate the condition properly:
def f1(cat_gen, pred):
for item in cat_gen:
if pred(item):
yield item
f1(flat, lambda a, b, c: ...)
f1(nested, lambda ab, c: ...)
Or, flatten the nested tuples before passing the iterable to f1:
def f1(cat_gen):
for a, b, c in cat_gen:
if ...:
yield a, b, c
f1(map(lambda ab, c: (ab[0], ab[1], c), nested))
You could define it like this
def f1(cat_gen):
# Figure out how to iterate, store it in condition_to_iterate
for item in cat_gen:
if condition_to_iterate:
(a, b), c = item
else:
a, b, c = item
# Do whatever you need with a, b, c
If you want to keep it as 1 function, with two different return forms (maybe not the cleanest decision but depends on the implementation) you'd want to do something like:
def f1(cat_gen, yield_method = 0):
for a, b, c in cat_gen:
if some condition:
if yield_method:
yield a, b, c
else:
yield (a, b), c
and just have the user be aware of the modes of return by that second argument.
Related
Let's say I have a Python constructor
def foo(a, b, c):
__def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
and I have a list of inputs
bar = [a, b, c]
Is there a way I can call the constructor with just a list of inputs? Eg,
foobar = foo(bar)
Or would I need to make an entire wrapper function, such as:
def fooWrapper(inputList):
a = inputList[0]
b = inputList[1]
c = inputList[2]
return foo(a, b, c)
Assuming I cannot change neither the constructor nor the way I receive the inputs (as a list), is there a more simple way to do this than creating a wrapper?
Thank you.
This should do the work for the wrapper function:
def f(a, b, c):
return sum([a, b, c])
bar = [3, 2, 1]
total = f(*bar)
print(total)
Outputs 6.
Since a constructor can not return a value, yes you need a wrapper.
I have defined three functions.
def evaluate1(a, b):
pass
def evaluate2(a, b):
pass
def evaluate3(a, b, c):
pass
What I want to do use a pointer to record which evaluate function I will use depending on the test inputs. The logic is as shown follows:
def test(a, b, c, d):
# let evaluate_function records which evaluate function I will use
if c > 1:
evaluate_function = evaluate3 # not sure
else:
if d:
evaluate_function = evaluate1
else:
evaluate_function = evaluate2
# execute the evaluate function
evaluate_function(a, b, ?)
However, since evaluate3 has different arguments from evaluate1 and evaluate3. How should I do? Thanks!
You have come up with a good idea of using a 'function pointer' to select the function. But since you know which function you are selecting at the time, you could also bind up the params:
def test(a, b, c, d):
# let evaluate_function records which evaluate function I will use
if c > 1:
evaluate_function = evaluate3 # not sure
params = a,b,d
else:
if d:
evaluate_function = evaluate1
params = a,b
else:
evaluate_function = evaluate2
params = a,c
# execute the evaluate function
evaluate_function(*params)
I'll leave it to you to properly select the params.
Why not just call the evaluate functions directly instead of assigning them to a function as so. Makes it more readable
def evaluate1(a, b):
print('evaluate1')
def evaluate2(a, b):
print('evaluate2')
def evaluate3(a, b, c):
print('evaluate3')
def test(a, b, c=None, d=None):
# let evaluate_function records which evaluate function I will use
if c and c > 1:
evaluate3(a, b, c)
else:
if d:
evaluate1(a, b)
else:
evaluate2(a, c)
test(1,2,c=0.1,d=1)
#evaluate1
test(1,2)
#evaluate2
test(1,2,3)
#evaluate3
Say I want to see if some objects (a,b,c) in an iterable are in object D. If none are in D, pass. If at least one is in D, all a b and c must be in D, or else an error is raised.
if any(i in D for i in (a,b,c)):
if all(i in D for i in (a,b,c)):
# do something
else:
raise Exception
Is there a more pythonic/less confusing way of doing this?
I would do the "x in D" test only once for each element:
ins = [i in D for i in (a, b, c)]
if any(ins):
if all(ins):
# do something
else:
raise Exception
And borrowing phihag's observation about the implication between all and any:
ins = [i in D for i in (a, b, c)]
if all(ins):
# do something
elif any(ins):
# raise error
If a, b, and c are hashable, you can use sets to express this with helpfully-named methods:
elements = {a, b, c}
if not elements.isdisjoint(D):
if elements.issubset(D):
do_whatever():
else:
raise Whatever
A compact way to express the condition could be:
S = {a, b, c}
if set(D) & S not in (set(), S):
raise Exception()
Your Python code is already an almost verbatim copy of your logic, so I doubt you can simplify the tests.
Since all(X) implies any(X) for non-empty X, you can, however, reorder them so that they are not nested:
props = (a, b, c)
if all(i in D for i in props):
# do something
elif any(i in D for i in props):
raise Exception('Either all or none')
Note that I also pulled out (a, b, c) into a helper variable, which may or may not improve clarity, depending on the complexity.
def fibonacci(num):
a=0
b=1
for i in range(num):
a, b=b, a+b
print a
How does the line inside the loop works?
Somehow a & b 's values change, can seems to understand how..
EDIT:
For some reason I got confused, thought that the middle exp of b=b is something new...
didn't read it well..
It really is (a,b) = (b, a+b) which is the basic form of swap in python (:
b, a+b creates a tuple
This tuple is unpacked back into a and b
This line a, b = b, a+b is equivalent to (a, b) = (b, a+b), which is a tuple assignment.
The line in question can be more clearly written (through tuple packing on the right side and sequence unpacking on the left side) as:
(a, b) = (b, a + b)
As the assignments to a and b are carried out in parallel, this is exactly the same as:
new_a = b
new_b = a + b
a = new_a
b = new_b
I am using Python and I would like to have an if statement with many variables in it.
Such as:
if A, B, C, and D >= 2:
print (A, B, C, and D)
I realize that this is not the correct syntax and that is exactly the question I am asking — what is the correct Python syntax for this type of an if statement?
You want to test a condition for all the variables:
if all(x >= 2 for x in (A, B, C, D)):
print(A, B, C, D)
This should be helpful if you're testing a long list of variables with the same condition.
If you needed to check:
if A, B, C, or D >= 2:
Then you want to test a condition for any of the variables:
if any(x >= 2 for x in (A, B, C, D)):
print(A, B, C, D)
Another idea:
if min(A, B, C, D) >= 2:
print A, B, C, D
I'd probably write this as
v = A, B, C, D
if all(i >= 2 for i in v):
print v
If you have ten variables that you are treating as a group like this, you probably want to make them elements of a list, or values in a dictionary, or attributes of an object. For example:
my_dict = {'A': 1, 'B': 2, 'C': 3 }
if all(x > 2 for x in my_dict.values()):
print "They're all more than two!"
How about:
if A >= 2 and B >= 2 and C >= 2 and D >= 2:
print A, B, C, D
For the general case, there isn't a shorter way for indicating that the same condition must be true for all variables - unless you're willing to put the variables in a list, for that take a look at some of the other answers.
Depending on what you are trying to accomplish, passing a list to a function may work.
def foo(lst):
for i in lst:
if i < 2:
return
print lst
Except that she's probably asking for this:
if A >= 2 and B >= 2 and C >= 2 and D >= 2: