Long variable assignment recommended wrapping - python

I have the following assignments in my __init__() method:
self.seat, self.feet, self.backrest, self.stabilizer_bar, self.packaged = False
I would like to make it compliant to PEP8, but the line is too long. I thought about using one line for each assignment, but it doesn't feel pythonic to type False 5 times.
What's the recommended way to wrap the line above?
EDIT:
I've changed False * 5 to False thanks to your comments. But still, how do I wrap the line?

Try wrapping the left side in parentheses, then splitting it. That usually works.
def __init__(self):
(self.seat, self.feet, self.backrest,
self.stabilizer_bar, self.packaged) = False, False, False, False, False
I don't know how this behaves in actual production code, but a quick run in PyScripter returns no error.

If you have a really long list of assignments, why not trying:
def __init__(self):
for prop in ['seat', 'feet', 'backrest', 'stabilizer_bar', 'packaged']:
setattr(self, prop, False)

In this specific case, I'd write the assignments line by line:
self.seat = False
self.feet = False
self.backrest = False
self.stabilizer_bar = False
self.packaged = False
Now assuming rather than False you have a function returning a tuple, I'd write it this way:
(self.seat, self.feet, self.backrest,
self.stabilizer_bar, self.packaged) = my_function()
as in TrueError's answer.

Related

Is it better to use 'elif' or consecutive 'if' statements alongside return statements?

This question is specifically regarding coding convention. I know that using if or elif in this case will produce the same results. Just wondering which is the "proper" way to construct this function:
With consecutive if:
def can_take(self, selectedCourse):
if selectedCourse.hasPassed():
return False
if selectedCourse.getPrereqs() != 'none':
for prereq in selectedCourse.getPrereqs():
if not self.courses[prereq].hasPassed():
return False
return True
With elif:
def can_take(self, selectedCourse):
if selectedCourse.hasPassed():
return False
elif selectedCourse.getPrereqs() != 'none':
for prereq in selectedCourse.getPrereqs():
if not self.courses[prereq].hasPassed():
return False
return True
If I had to choose between the two, I would probably use two if statements, but that's just a matter of personal preference.
If I had a third choice, I wouldn't have any return statements with Boolean literals. I would write a single return statement that uses and and or.
return (not selected.hasPassed()
and (selected.getPrereqs() == 'none'
or all(x.hasPassed()
for x in selected.getPrereqs()))
This is close to how you would describe this in English: you can take the class if you have not passed it, and if the class either has no prerequisites or if you have passed all the prerequisites.
As John Kugelman points out, if getPrereqs returned an empty list instead of 'none', you could further reduce this to
return (not selected.hasPassed()
or all(x.hasPassed()
for x in selected.getPrereqs())
I love the early return pattern:
Get invalid cases out of the way first, either simply exiting or raising exceptions as appropriate, put a blank line in there, then add the "real" body of the method. I find it easier to read.
Returning early keeps the nesting level down, which is great way to reduce cognitive load. I would take it one step further and flip the second if statement around so it too returns early:
def can_take(self, selectedCourse):
if selectedCourse.hasPassed():
return False
if selectedCourse.getPrereqs() == 'none':
return True
for prereq in selectedCourse.getPrereqs():
if not self.courses[prereq].hasPassed():
return False
return True
That said, some other improvements I would make:
Avoid stringly typed variables. Switch that 'none' to None.
But then, when a method returns a list don't return None when there are no results. Return an empty list. Then the caller can blindly iterate over the list without checking if it's None or empty.
def can_take(self, selectedCourse):
if selectedCourse.hasPassed():
return False
for prereq in selectedCourse.getPrereqs():
if not self.courses[prereq].hasPassed():
return False
return True
If you're comfortable with generator expressions you could even convert the loop into an all(...) call, removing the need for the final return True.
def can_take(self, selectedCourse):
if selectedCourse.hasPassed():
return False
return all(self.courses[prereq].hasPassed()
for prereq in selectedCourse.getPrereqs())
I like this because it's a more direct encoding of the question: "Has the student passed all of the prereqs?"
I think I prefer the first version. Why? When you have an if...elif...elif... thing with returns in each branch, there are two "competing" control structures: the if statement and the returns. Obviously, the returns will "win", so we might as well remove the elif stuff. Either that, or have just one return statement, which returns a value computed by a preceding if...elif...elif...else structure.
We use elif but please understand it depends on your problem statement.
Note: Please do not create a big ladder out of it as then it becomes difficult to maintain and debug the code.

Python: using a function that returns two items in an If statement, without executing twice

I have a function I'm using to test in an if/then.
The issue is that I'm executing the function BOTH in the if conditional, and then again after the if statement because the function returns two items.
This just seems wasteful and I'm trying to think of ways to improve this. Here's a really basic version of what I'm trying to avoid: "True" is returned to allow the condition to pass, but then then "coolstuff()" is executed again to get more information from the function.
"coolstuff()" could possibly return false, so I can't use the returned string "stuff" as the test.
def coolstuff():
return True, "stuff"
if coolstuff()[0]:
coolthing = coolstuff()[1]
print coolthing
There's gotta be a better way to do this, no? My brain is melting a little as I try to hash it out.
I basically want to do something like this (invalid) syntax:
def coolstuff():
return True, "stuff"
if a, b == coolstuff() and a:
print b
Just collect both results into variables
a, b = fn()
if a:
# work with b
def coolstuff():
if valid:
return "stuff"
return None
data = coolstuff()
if data:
print(data)
Call the function and capture the entire returned value:
x = coolstuff()
Now you have access to both parts of the returned value, in x[0] and x[1].
Store it:
state, coolvar = coolstuff()
if state:
do_whatever(coolvar)
If in newer Python, you could use the dreaded walrus (but I prefer ti7's approach of just assigning in a separate line):
if (x := coolstuff())[0]:
print(x[1])

How to check if an attribute is True in Python

I want to look if an object.est_devoilee is True : I need to make conditions.
If object.devoiler is True : do that.
If object.devoiler is not True: do that.
At first, my objet have self.est_devoilee = False and when I use object.devoiler, it becomes self.est_devoilee = True with that def :
def devoiler(self):
self.est_devoilee = True
I have tried
if object.devoiler() == True:
I have tried
if case.devoiler() is not True:
But I feel it's not really checking if self.est_devoilee have been used before. It's as if it always returns true because def devoiler(self): does not return a boolean? I only want to check if object.est_devoilee = True but I don't know how!
Sorry for my spelling, I am french. Thank you!
The devoiler() method is not used to get the value of the attribute, it just sets it to True. If you want to check it, just access the attribute:
if case.est_devoiler:
# do something

Is using min/max on boolean lists in Python bad?

So I have a condition I want to happen only when all items in a list evaluate to true. An example of this might be something like a list of functions which return a boolean (not actually my situation but easier to explain):
def foo():
# do something
def bar():
# do something
def baz():
# do something
fncs = [foo, bar, baz]
if <every element in [fnc() for fnc in fncs] evaluates to true>:
# do something
I know I can definitely do this:
all_true = True
for fnc in fncs:
if not fnc():
all_true = False
if all_true:
# do something
But, I was wondering if this is poor form:
if min([fnc() for fnc in fncs]):
# do something
Alternatively, I could try to select all false elements during list comprehension and check whether the list is occupied (this works because bool(arr) where arr is a list returns False if and only if arr is empty):
if not [None for fnc in fncs if not fnc()]:
# do something
I feel like the "min" is a lot cleaner than the last method, and while the first one is easiest to understand for novices it should be pretty clear what's going on. I could alternately make it clearer through aliasing:
all_true = min
if all_true([fnc() for fnc in fncs]):
# do something
I'm sure I missed other ways to do this as well. I'm wondering what method would be most desirable.
Thanks for the help!
Using min is not "bad", but it is unclear what you are trying to do and will do unnecessary work. You should use all instead.
if all(fnc() for fnc in fncs):
# do something
This will return True if all values are True, and False otherwise. It has the added benefit of quitting early if any value is False, unlike min which must run through the entire sequence at least once.
If you find that you need to evaluate if the are all False, I recommend any (well, not any(...), specifically) which has a similar "quit as soon as possible" behavior.
You're probably looking for all built-in function:
print all(f() for f in [foo, bar, baz])

Pythonic way to get boolean value of object

I'd like opinions on the most idiomatic way to write a function that returns True if an object is truthy, and False otherwise. For example:
is_truthy(True) # True
is_truthy(False) # False
is_truthy(123) # True
is_truthy(0) # False
is_truthy("some string") # True
is_truthy("") # False
The best I've come up with is this:
def is_truthy(obj):
return not not obj
Can anybody do better?
is_truthy = bool
The builtins got you covered.
You can do it like this:
bool(obj)
If you need a bool it's because you will end up using it in if statements and the like. I don't think you need to encapsulate anything within an is truthy function; just use the bool directly. I.e. rather than:
if is_truthy(my_bool):
# do something
simply do:
if my_bool:
# do something

Categories