I recently had to implement a small check for any variables that might have not been initialized (and their default value is None). I came up with this:
if None in (var1, var2, var3):
error_out()
While, in my eyes, bordering on beautiful, I was wondering - is this a good way to do it? Is this the way to do it? Are there any cases in which this would produce some unexpected results?
First things first: your code is valid, readable, concise... so it might not be the way to do it (idioms evolves with time and new language features) but it certainly is one of the way to do it in a pythonic way.
Secondly, just two observations:
The standard way to generate errors in python is to raise Exceptions. You can of course wrap your exception-raising within a function, but since it's quite unusual I was just wondering if you chose this design for some specific reason. Since you can write your own Exception class, even boilerplate code like logging an error message to file could go within the class itself rather than in the wrapping function.
The way you wrote your test is such that you won't be able to assign None as a value to your variables. This might be not a problem now, but might limit your flexibility in the future. An alternative way to check for initialisation could be to simply not declare an initial value for the variable in question and then do something along the lines of:
try:
self.variable_name
except NameError:
# here the code that runs if the variable hasn't been initialised
finally:
# [optional] here the code that should run in either case
A just slightly different way to do it would be to use the built-in all method; however, this will also catch false-ish values like 0 or "", which may not be what you want:
>>> all([1, 2, 3])
True
>>> all([None, 1, 2])
False
>>> all([0, 1])
False
Allow me to leave my two cents here:
>>> any(a is None for a in [1,0])
False
>>> any(a is None for a in [1,0, None])
True
So one can:
def checkNone(*args):
if any(arg is None for arg in args):
error_out()
Nothing new here. Just IMHO maybe the part any arg is None is more readable
Related
Sometimes a function gives a return value which you'd just want to discard rather than send to the output stream. What would be the elegant way to handle this?
Note that we're talking about a function that returns something which you cannot change.
def fn():
return 5
I personally have used null before, but I'm looking for a more pythonic way:
null = fn()
The standard way to show this is to assign the results you don't want to _. For instance, if a function returns two values but you only want the first, do this:
value, _ = myfunction(param)
Most Python linters will recognize the use of _ and not complain about unused variables.
If you want to ignore all returns, then simply don't assign to anything; Python doesn't do anything with the result unless you tell it to. Printing the result is a feature in the Python shell only.
I really like the idea of assigning to null - but it does have an unexpected side-effect:
>>> print divmod(5, 3)
(1, 2)
>>> x, null = divmod(5, 3)
>>> print null
2
For those who code mostly in Python, this is probably not an issue: null should be just as much a junk value as _.
However, if you're switching between other languages like Javascript, it's entirely possible to accidentally write a comparison with null instead of None. Rather than spitting the usual error about comparing with an unknown variable, Python will just silently accept it, and now you're getting true and false conditions that you totally don't expect... this is the sort of error where you stare at the code for an hour and can't figure out wth is wrong, until it suddenly hits you and you feel like an idiot.
The obvious fix doesn't work, either:
>>> x, None = divmod(5, 3)
File "<stdin>", line 1
SyntaxError: cannot assign to None
...which is really disappointing. Python (and every other language on the planet) allows all of the parameters to be implicitly thrown away, regardless of how many variables are returned:
>>> divmod(5, 3)
...but explicitly throwing away parameters by assigning them to None isn't allowed?
It feels kind of stupid of the Python interpreter to characterize assigning to None as a syntax error, rather than an intentional choice with an unambiguous result. Can anyone think of a rationale for that?
Is there any harm if we use many return positions in a python function ?
Like suppose if I want to return a function if value is not 3 and value is not None (Just a scenario). So it can be done in so many ways like
def return_value(value):
if value != 3:
return None
if value is not None:
return None
if value != 'string':
return None
or It can be done like this:
def return_value(value):
if value != 3 or value is not None or value !='string':
return None
Again, I would like to use second way of writing code only, but just for a doubt I am asking having many returns somehow affects the performance of function or not ?
No, there is no harm in having many returns.
That said, I would in this case definitely go with the second version. The first is harder to read, and slower (although optimizing for speed without a benchmark is always premature). It is not the many returns that make its lower though, but the many ifs.
It seems a very interesting scenario that you have used above, but conceptually there is no issue with multiple return points in a function.
In a real scenario, it is likely that your test conditions will be logically similar, and that grouping them together, as in your second example, will make good logical sense and keep your code easy to read.
Cheers
Right now, I have the following class methods:
def check_capacity(self, at_index)
def update_capacity(self, at_index)
The former returns a Boolean, while the latter changes an instance variable. The problem is both methods do very similar things. I feel like I'm violating DRY?
I'd like to have one method:
def update_capacity(self, at_index)
which I can use as:
if update_capacity(at_index):
that would create the intended side-effects if the side-effects are desirable, and return False otherwise.
My attempt was to copy the instance variable, check to see if the copy was desirably changed, and then set the instance variable to the copy if correct and return True, or don't and return False otherwise. However, this doesn't work with mutable data structures (like lists)!
Should I just be doing this with a "deep copy"? Or is there a better way to go about doing this? I'd like to be as Pythonic as possible.
EDIT
The check_capacity iterates through the instance variable and checks if making the change would violate a condition.
The update_capacity iterates through the instance variable and makes the change, knowing the condition won't be violated.
Both have very similar code.
I have a hunch that those two functions together manage to straddle your problem without exactly hitting it on the head. If I have this right, you want to have update_capacity either change something or return False if changing something is not desired.
It seems to me that you will be able to achieve this functionality by adding the checking mechanism from check_capacity into update_capacity, performing the condition check before executing the body of update_capacity:
def update_capacity(self, at_index):
if <condition from check_capacity>:
<body of update_capacity>
else:
return False
Of course, this code will return None if the condition is true, so if you want to keep your function signatures tidy, you could return True or something depending on what fits the rest of your code.
If check_capacity is applied to more than one places, make it
a decorator that makes sure it throws an exception if the constraint/check
is not met.
Like
#check_capacity
def update_capacity(...)
# Does the job and does not return anything
If check_capacity is not used anywhere else, just put the logic inside
update_capacity.
Edit:
Also this
if update_capacity(at_index):
is ambiguous at best. Is the function going to see if I can update? Is it going to actually update/mutate something?
It is evident that these 2 functions must be separate.
I find myself writing a lot of code that resembles the following:
ans = call_function()
if ans:
return ans
...
Is there a clean way to make this a 1 or 2 liner? An "example" of such a paradigm might be
if x as call_function():
return x
It seems that as long as ans is not None, you can just return it, based on your implied usage.
if ans is not None:
return ans
I'm not sure what you're doing after your if, but perhaps you're doing the following:
ans = call_function()
if ans:
return ans
else:
return default
In which case it you can simply do:
return call_function() or default
It may make sense to refactor the code which would follow your if statement into another function. There is a (not unwise) school of thought which emphasizes making each function do one very specific thing.
In this case, you could write something like this:
ans = call_function()
return ans if ans is not None else following_code()
or, if you are really testing for a truthy value (rather than specifically testing for not None):
return call_function() or following_code()
In the not None case, you can still avoid assigning to the temp variable ans by writing a function like this:
def fallback(test_value, routine, *args, **kwargs):
return test_value if test_value is not None else routine(*args, **kwargs)
and then using it like this:
return fallback(call_function(), following_code,
arg_to_following_code, following_code_kwarg=keywordarg_value)
This might be useful if you're doing this sort of thing very frequently, but in general it will just make your code a bit harder to read, because people will not be familiar with your fallback function. The original form used in your question is bulky, but it has a readily recognizable shape that people will be used to seeing. It also does things in a very measured fashion, one logical action per line, as is the norm in Python.
On the other hand, it can be good to cut out extraneous local variables, since these can lead to bugs due to typos or confusion about scope.
Wanting to embed assignments in if statements is probably one of the more common feature requests we see for Python. The problem is that such embedded assignment proposals typically only work for the very limited cases where the value you want to store and the condition you want to check are identical (e.g. your example falls into that trap and would be useless if you instead needed to check a more specific condition like if ans is not None:).
If the extra line really offends you, you can collapse the if statement to a one-liner (if ans: return ans). A lot of people hate that style, though.
However, I question your basic premise that "I want to know if this function returns something meaningful, and if it is, then that is the result of this function as well, otherwise I will fall back and calculate my result some other way" isn't sufficient justification for using a properly scoped local variable.
Knowing whether or not another function has finished the job for you sounds pretty damn important to me.
My work place has imposed a rules for no use of exception (catching is allowed). If I have code like this
def f1()
if bad_thing_happen():
raise Exception('bad stuff')
...
return something
I could change it to
def f1()
if bad_thing_happen():
return [-1, None]
...
return [0, something]
f1 caller would be like this
def f1_caller():
code, result = f1(param1)
if code < 0:
return code
actual_work1()
# call f1 again
code, result = f1(param2)
if code < 0:
return code
actual_work2()
...
Are there more elegant ways than this in Python ?
Exceptions in python are not something to be avoided, and are often a straightforward way to solve problems. Additionally, an exception carries a great deal of information with it that can help quickly locate (via stack trace) and identify problems (via exception class or message).
Whoever has come up with this blanket policy was surely thinking of another language (perhaps C++?) where throwing exceptions is a more expensive operation (and will reduce performance if your code is executing on a 20 year old computer).
To answer your question: the alternative is to return an error code. This means that you are mixing function results with error handling, which raises (ha!) it's own problems. However, returning None is often a perfectly reasonable way to indicate function failure.
Returning None is reasonably common and works well conceptually. If you are expecting a return value, and you get none, that is a good indication that something went wrong.
Another possible approach, if you are expecting to return a list (or dictionary, etc.) is to return an empty list or dict. This can easily be tested for using if, because an empty container evaluates to False in Python, and if you are going to iterate over it, you may not even need to check for it (depending on what you want to do if the function fails).
Of course, these approaches don't tell you why the function failed. So you could return an exception instance, such as return ValueError("invalid index"). Then you can test for particular exceptions (or Exceptions in general) using isinstance() and print them to get decent error messages. (Or you could provide a helper function that tests a return code to see if it's derived from Exception.) You can still create your own Exception subclasses; you would simply be returning them rather than raising them.
Finally, I would work toward getting this ridiculous policy changed, as exceptions are an important part of how Python works, have low overhead, and will be expected by anyone using your functions.
You have to use return codes. Other alternatives would involve mutable global state (think C's errno) or passing in a mutable object (such as a list), but you almost always want to avoid both in Python. Perhaps you could try explaining to them how exceptions let you write better post-conditions instead of adding complication to return values, but are otherwise equivalent.