I know it is bad convention/design to conditionally declare a variable. i.e.:
if some_boolean:
x = 1
where x is not declared anywhere else. But is it bad to conditionally declare a variable if you only use it later on if that condition is met?
if some_boolean and some_other_boolean:
x+=1
It's dubious style, as it's prone to bugs based on imperfect, impartial understanding on some future maintainer's part. I also think that initially setting variables to None (unless more useful values are known for them) is helpful to readability, in part because it gives you one, natural place to document all of the variables with comments (rather than spreading such comments all over the place, which makes them hard to find;-).
if your code look like this
if some_boolean:
x = 1
# some actions
# not changing some_boolean
# but calculating some_other_boolean
# ...
if some_boolean and some_other_boolean:
x+=1
Can it be refactored to
def some_actions(some_args,...):
#...
def calculate_some_other_boolean(some_other_args,...):
#...
if some_boolean:
x = 1
some_actions(some_args,...)
if calculate_some_other_boolean(some_other_args,...):
x+=1
else:
some_actions(some_args,...)
?
From a very simple design perspective, I'd just default the boolean to false even if it maybe won't be used later. That way the boolean in question is not maybe defined or maybe actually a boolean value, and in the event that it is used, it has a proper value.
If you have two or three booleans set to false and they never get used, it's not going to make any significant difference in a big picture sense. If you have more than a few, though, it may indicate a design problem.
Related
I'm trying to understand what 'implicit' and 'explicit' really means in the context of Python.
a = []
# my understanding is that this is implicit
if not a:
print("list is empty")
# my understanding is that this is explicit
if len(a) == 0:
print("list is empty")
I'm trying to follow the Zen of Python rules, but I'm curious to know if this applies in this situation or if I am over-thinking it?
The two statements have very different semantics. Remember that Python is dynamically typed.
For the case where a = [], both not a and len(a) == 0 are equivalent. A valid alternative might be to check not len(a). In some cases, you may even want to check for both emptiness and listness by doing a == [].
But a can be anything. For example, a = None. The check not a is fine, and will return True. But len(a) == 0 will not be fine at all. Instead you will get TypeError: object of type 'NoneType' has no len(). This is a totally valid option, but the if statements do very different things and you have to pick which one you want.
(Almost) everything has a __bool__ method in Python, but not everything has __len__. You have to decide which one to use based on the situation. Things to consider are:
Have you already verified whether a is a sequence?
Do you need to?
Do you mind if your if statement crashed on non-sequences?
Do you want to handle other falsy objects as if they were empty lists?
Remember that making the code look pretty takes second place to getting the job done correctly.
Though this question is old, I'd like to offer a perspective.
In a dynamic language, my preference would be to always describe the expected type and objective of a variable in order to offer more purpose understanding. Then use the knowledge of the language to be succinct and increase readability where possible (in python, an empty list's boolean result is false). Thus the code:
lst_colours = []
if not lst_colours:
print("list is empty")
Even better to convey meaning is using a variable for very specific checks.
lst_colours = []
b_is_list_empty = not lst_colours
if b_is_list_empty:
print("list is empty")
Checking a list is empty would be a common thing to do several times in a code base. So even better such things in a separate file helper function library. Thus isolating common checks, and reducing code duplication.
lst_colours = []
if b_is_list_empty(lst_colours):
print("list is empty")
def b_is_list_empty (lst):
......
Most importantly, add meaning as much as possible, have an agreed company standard to chose how to tackle the simple things, like variable naming and implicit/explicit code choices.
Try to think of:
if not a:
...
as shorthand for:
if len(a) == 0:
...
I don't think this is a good example of a gotcha with Python's Zen rule of "explicit" over "implicit". This is done rather mostly because of readability. It's not that the second one is bad and the other is good. It's just that the first one is more skillful. If one understands boolean nature of lists in Python, I think you find the first is more readable and readability counts in Python.
I'm new to coding and I'm a little confused. How/why can a for loop use a variable that isn't defined yet?
For example:
demond = {'green':'grass', 'red':'fire', 'yellow':'sun'}
for i in demond:
print(i)
Output:
green
yellow
red
In python, you don't need to declare variables. In C/C++/JAVA etc. you will have to declare them first and then use them.
Variables are nothing but reserved memory locations to store values.Based on the data type of a variable, the interpreter allocates memory and decides what can be stored in the reserved memory.Python variables do not need explicit declaration to reserve memory space. The declaration happens automatically when you assign a value to a variable.
There are two things that you need to keep in mind:
because Python is a weakly-typed language, you do not need to explicitly declare any variable to a certain object type. This is something you already know, and why you can assign things without having to state what type they will be.
For loop constructs do a lot of things in the background that you don't explicitly see. This means that although it doesnt LOOK like anything is being defined, it is.
With that in mind, I dont want to really explain how for loops work, because there are already answers available for that but the main point is that a for loop in python is the same as the following pseudo code.
#set up your iterable
demond = SOME_ITERABLE_OBJECT (this can be a list, string, dict, etc)
#this
for i in demond:
do_something(i)
#is the same as this
i = demond[0] # the first item in demond
do_something(i)
i = demond[1] # the second item in demond
do_something(i)
i = demond[2]
...
...
..
i = demond[n] # the last item in demond
do_something(i)
Now your follow up question may be this: what makes it so that, in your code, for i in demond sets i to equal to it's keys? Well that is just part of the design of python, specifically how dicts work. What the for loop is ACTUALLY doing is calling an iterables next() function until the iterable generator is done. Each iterable can have a different result from a for loop (see the first link).
NOTE:
In my code example, I am setting i = demond[some_index]. This looks like a list index grab but it is really meant to just show that is iterating through the list in some sort of order. IT IS PSUEDO CODE. Just keep that in mind.
I am new to Python.
Assume I have a dictionary which holds power supply admin state.
(OK = Turned on. FAIL = Turned off).
There are several way to write the "get" function:
1st way
is_power_supply_off(dictionary)
gets the admin state from dictionary.
returns true if turned off.
returns false if turned on.
is_power_supply_on(dictionary)
gets the admin state from dictionary.
returns true if turned on.
returns false if turned off.
2nd way
is_power_supply_on_or_off(dictionary, on_or_off)
gets the admin state from dictionary.
returns true/false based on the received argument
3rd way
get_power_supply_admin_state(dictionary)
gets the admin state from dictionary.
return value.
Then, I can ask in the function which calls the get function
if get_power_supply_admin_state() == turned_on/turned_off...
My questions are:
Which of the above is considered best practice?
If all three ways are OK, and it`s just a matter of style, please let me know.
Is 1st way considered as "code duplication"? I am asking this because I can combine the two functions to be just one (by adding an argument, as I did in the 2nd way. Still, IMO, 1st way is more readable than 2nd way.
I will appreciate if you can share your thoughts on EACH of the ways I specified.
Thanks in advance!
I would say that the best approach would be to have only a is_power_supply_on function. Then, to test if it is off, you can do not is_power_supply_on(dictionary).
This could even be a lambda (assuming state is the key of the admin state)::
is_power_supply_on = lambda mydict: mydict['state'].lower() == 'ok'
The problem with the first approach is that, as you say, it wastes codes.
The problem with the second approach is that, at best, you save two characters compared to not (if you use 0 or 1 for on_or_off), and if you use a more idiomatic approach (like on=True or on_or_off="off") you end up using more characters. Further, it results in slower and more complicated code since you need to do anif` test.
The problem with the third approach is in most cases you will also likely be wasting characters compared to just getting the dict value by key manually.
Even if this solution isn't in your propositions, I think the most pythonic way of creating getters is to use properties. As it, you'll be able to know whether the power supply is on or off, but the user will use this property as it was a simple class member:
#property
def state(self):
# Here, get whether the power supply is on or off
# and put it in value
return value
Also, you could create two class constants, PowerSupply.on = True and PowerSupply.off = False, which would make the code easier to understand
The general Pythonic style is to not repeat yourself unnecessarily, so definitely the first method seems pointless because it's actually confusing to follow (you need to notice whether it's on or off)
I'd gravitate most to
get_power_supply_admin_state(dictionary)
gets the admin state from dictionary
return value
And, if I'm reading this correctly, you could go even further.
power_supply_on(dictionary)
return the admin state from dictionary == turned on
This will evaluate to True if it's on and False otherwise, creating the simplest test because then you can run
if power_supply_on(dictionary):
It's more Pythonic to store the dictionary in a class:
class PowerSupply(object):
def __init__(self):
self.state = {'admin': 'FAIL'}
def turn_on(self):
self.state['admin'] = 'OK'
def is_on(self):
return self.state['admin'] == 'OK'
(add more methods as needed)
Then you can use it like this:
ps = PowerSupply()
if not ps.is_on():
# send an alert!
result = is_power_supply_off(state)
result = is_power_supply_on(state)
result = not is_power_supply_on(state) # alternatively, two functions are certainly not needed
I strongly prefer this kind of naming for sake of readability. Let's just consider alternatives, not in function definition but where function is used.
result = is_power_supply_on_or_off(state, True)
pass
result = is_power_supply_on_or_off(state, False)
pass
if get_power_supply_admin_state(state):
pass
if not get_power_supply_admin_state(state):
pass
All of these codes requires map of what True and False means in this context. And to be honest, is not that clear. In many embedded systems 0 means truthy value. What if this function analyses output from system command? 0 (falsy) value is indicator of correct state/execution. In a result, intuitive True means OK is not always valid. Therefore I strongly advice for first option - precisely named function.
Obviously, you'll have some kind of private function like _get_power_supply_state_value(). Both function will call it and manipulate it's output. But point is - it will be hidden inside a module which knows what means what considering power supply state. Is implementation detail and API users does not need to know it.
While writing state machines to analyze different types of text data, independent of language used (VBA to process .xls contents using arrays/dictionaries or PHP/Python to make SQL insert queries out of .csv's) I often ran into neccesity of something like
boolean = False
while %sample statement%:
x = 'many different things'
if boolean == False:
boolean = True
else:
%action that DOES depend on contents of x
that need to do every BUT first time I get to it%
Every time I have to use a construction like this, I can't help feeling noob. Dear algorithmic gurus, can you assure me that it's the only way out and there is nothing more elegant? Any way to specify that some statement should be "burnt after reading"? So that some stupid boolean is not going to be checked each iteration of the loop
The only things that come across as slightly "noob" about this style are:
Comparing a boolean variable to True or False. Just write if <var> or if not <var>. (I'll ignore the = vs == as a typo!)
Not giving the boolean variable a good name. I know that here boolean is just a placeholder name, but in general using a name like first_item_seen rather than something generic can make the code a lot more readable:
first_item_seen = False
while [...]:
[...]
if first_item_seen:
[...]
else:
first_item_seen = True
Another suggestion that can work in some circumstances is to base the decision on another variable that naturally conveys the same state. For instance, it's relatively common to have a variable that contains None for the first iteration, but contains a value for later iterations (e.g. the result so far); using this can make the code slightly more efficient and often slightly clearer.
If I understand your problem correctly, I'd try something like
x = 'many different things'
while %sample statements%:
x = 'many different things'
action_that_depends_on_x()
It is almost equivalent; the only difference is that in your version the loop body could be never executed (hence x never being computed, hence no side effects of computing x), in my version it is always computed at least once.
In an answer (by S.Lott) to a question about Python's try...else statement:
Actually, even on an if-statement, the
else: can be abused in truly terrible
ways creating bugs that are very hard
to find. [...]
Think twice about else:. It is
generally a problem. Avoid it except
in an if-statement and even then
consider documenting the else-
condition to make it explicit.
Is this a widely held opinion? Is else considered harmful?
Of course you can write confusing code with it but that's true of any other language construct. Even Python's for...else seems to me a very handy thing to have (less so for try...else).
S.Lott has obviously seen some bad code out there. Haven't we all? I do not consider else harmful, though I've seen it used to write bad code. In those cases, all the surrounding code has been bad as well, so why blame poor else?
No it is not harmful, it is necessary.
There should always be a catch-all statement. All switches should have a default. All pattern matching in an ML language should have a default.
The argument that it is impossible to reason what is true after a series of if statements is a fact of life. The computer is the biggest finite state machine out there, and it is silly to enumerate every single possibility in every situation.
If you are really afraid that unknown errors go unnoticed in else statements, is it really that hard to raise an exception there?
Saying that else is considered harmful is a bit like saying that variables or classes are harmful. Heck, it's even like saying that goto is harmful. Sure, things can be misused. But at some point, you just have to trust programmers to be adults and be smart enough not to.
What it comes down to is this: if you're willing to not use something because an answer on SO or a blog post or even a famous paper by Dijkstra told you not to, you need to consider if programming is the right profession for you.
I wouldn't say it is harmful, but there are times when the else statement can get you into trouble. For instance, if you need to do some processing based on an input value and there are only two valid input values. Only checking for one could introduce a bug.
eg:
The only valid inputs are 1 and 2:
if(input == 1)
{
//do processing
...
}
else
{
//do processing
...
}
In this case, using the else would allow all values other than 1 to be processed when it should only be for values 1 and 2.
To me, the whole concept of certain popular language constructs being inherently bad is just plain wrong. Even goto has its place. I've seen very readable, maintainable code by the likes of Walter Bright and Linus Torvalds that uses it. It's much better to just teach programmers that readability counts and to use common sense than to arbitrarily declare certain constructs "harmful".
If you write:
if foo:
# ...
elif bar:
# ...
# ...
then the reader may be left wondering: what if neither foo nor bar is true? Perhaps you know, from your understanding of the code, that it must be the case that either foo or bar. I would prefer to see:
if foo:
# ...
else:
# at this point, we know that bar is true.
# ...
# ...
or:
if foo:
# ...
else:
assert bar
# ...
# ...
This makes it clear to the reader how you expect control to flow, without requiring the reader to have intimate knowledge of where foo and bar come from.
(in the original case, you could still write a comment explaining what is happening, but I think I would then wonder: "Why not just use an else: clause?")
I think the point is not that you shouldn't use else:; rather, that an else: clause can allow you to write unclear code and you should try to recognise when this happens and add a little comment to help out any readers.
Which is true about most things in programming languages, really :-)
Au contraire... In my opinion, there MUST be an else for every if. Granted, you can do stupid things, but you can abuse any construct if you try hard enough. You know the saying "a real programer can write FORTRAN in every language".
What I do lots of time is to write the else part as a comment, describing why there's nothing to be done.
Else is most useful when documenting assumptions about the code. It ensures that you have thought through both sides of an if statement.
Always using an else clause with each if statement is even a recommended practice in "Code Complete".
The rationale behind including the else statement (of try...else) in Python in the first place was to only catch the exceptions you really want to. Normally when you have a try...except block, there's some code that might raise an exception, and then there's some more code that should only run if the previous code was successful. Without an else block, you'd have to put all that code in the try block:
try:
something_that_might_raise_error()
do_this_only_if_that_was_ok()
except ValueError:
# whatever
The issue is, what if do_this_only_if_that_was_ok() raises a ValueError? It would get caught by the except statement, when you might not have wanted it to. That's the purpose of the else block:
try:
something_that_might_raise_error()
except ValueError:
# whatever
else:
do_this_only_if_that_was_ok()
I guess it's a matter of opinion to some extent, but I personally think this is a great idea, even though I use it very rarely. When I do use it, it just feels very appropriate (and besides, I think it helps clarify the code flow a bit)
Seems to me that, for any language and any flow-control statement where there is a default scenario or side-effect, that scenario needs to have the same level of consideration. The logic in if or switch or while is only as good as the condition if(x) while(x) or for(...). Therefore the statement is not harmful but the logic in their condition is.
Therefore, as developers it is our responsibility to code with the wide scope of the else in-mind. Too many developers treat it as a 'if not the above' when in-fact it can ignore all common sense because the only logic in it is the negation of the preceding logic, which is often incomplete. (an algorithm design error itself)
I don't then consider 'else' any more harmful than off-by-ones in a for() loop or bad memory management. It's all about the algorithms. If your automata is complete in its scope and possible branches, and all are concrete and understood then there is no danger. The danger is misuse of the logic behind the expressions by people not realizing the impact of wide-scope logic. Computers are stupid, they do what they are told by their operator(in theory)
I do consider the try and catch to be dangerous because it can negate handling to an unknown quantity of code. Branching above the raise may contain a bug, highlighted by the raise itself. This is can be non-obvious. It is like turning a sequential set of instructions into a tree or graph of error handling, where each component is dependent on the branches in the parent. Odd. Mind you, I love C.
There is a so called "dangling else" problem which is encountered in C family languages as follows:
if (a==4)
if (b==2)
printf("here!");
else
printf("which one");
This innocent code can be understood in two ways:
if (a==4)
if (b==2)
printf("here!");
else
printf("which one");
or
if (a==4)
if (b==2)
printf("here!");
else
printf("which one");
The problem is that the "else" is "dangling", one can confuse the owner of the else. Of course the compiler will not make this confusion, but it is valid for mortals.
Thanks to Python, we can not have a dangling else problem in Python since we have to write either
if a==4:
if b==2:
print "here!"
else:
print "which one"
or
if a==4:
if b==2:
print "here!"
else:
print "which one"
So that human eye catches it. And, nope, I do not think "else" is harmful, it is as harmful as "if".
In the example posited of being hard to reason, it can be written explicitly, but the else is still necessary.
E.g.
if a < 10:
# condition stated explicitly
elif a > 10 and b < 10:
# condition confusing but at least explicit
else:
# Exactly what is true here?
# Can be hard to reason out what condition is true
Can be written
if a < 10:
# condition stated explicitly
elif a > 10 and b < 10:
# condition confusing but at least explicit
elif a > 10 and b >=10:
# else condition
else:
# Handle edge case with error?
I think the point with respect to try...except...else is that it is an easy mistake to use it to create inconsistent state rather than fix it. It is not that it should be avoided at all costs, but it can be counter-productive.
Consider:
try:
file = open('somefile','r')
except IOError:
logger.error("File not found!")
else:
# Some file operations
file.close()
# Some code that no longer explicitly references 'file'
It would be real nice to say that the above block prevented code from trying to access a file that didn't exist, or a directory for which the user has no permissions, and to say that everything is encapsulated because it is within a try...except...else block. But in reality, a lot of code in the above form really should look like this:
try:
file = open('somefile','r')
except IOError:
logger.error("File not found!")
return False
# Some file operations
file.close()
# Some code that no longer explicitly references 'file'
You are often fooling yourself by saying that because file is no longer referenced in scope, it's okay to go on coding after the block, but in many cases something will come up where it just isn't okay. Or maybe a variable will later be created within the else block that isn't created in the except block.
This is how I would differentiate the if...else from try...except...else. In both cases, one must make the blocks parallel in most cases (variables and state set in one ought to be set in the other) but in the latter, coders often don't, likely because it's impossible or irrelevant. In such cases, it often will make a whole lot more sense to return to the caller than to try and keep working around what you think you will have in the best case scenario.