I know I can add some if blocks around to avoid this problem, but I am looking for a best practice or good/nice way to handle this kind of programming problem.
I am looping through the result of a function, without storing the result first in a separate variable; something like this:
for item in mycustimitemgetter.itter():
dosomething()
The itter function is returning None instead of an empty list [], and Python throws an exception per None. This is correct python behavior and nothing's wrong with it. But I'm looking for a best practice solution to:
a) keep the code clean and simple (not storing the result in a var and do if != None, etc..)
b) treat a None return value like an empty list i.e. do not run the loop and silently ignore the fact that function returned a None value.
Perhaps, use the fact that both [] and None evaluate as False, but lists with contents don't:
for item in (mycustimitemgetter.itter() or []):
dosomething()
You have a method called itter() which returns an iterable object. I would say that given the name of the function, it's reasonable to say "the returned value should always be iterable". So, if you're returning a list, you should return an empty list if you have no values.
Code there to be executed. There is nothing wrong with adding:
if retval is None:
return []
return retval
or
return retval or []
to the end of your itter() implementation, depending on the types in use.
Consider this: you wrote the code and you're facing this problem. What about someone else who's trying to use your code without knowing what you know. What do they expect?
Alternatively you should use Generators (if suitable). They contain a 'next' method (see the docs at the link), which you can return false if there are no values.
Related
I am using a python script to do a cypher statement that should return 0..n results. I use a foreach loop to get all values:
for column1 in results['col1']:
# do some stuff
If the Statementresult is empty, the loop will not be executed - of course. I want to check the Statementresult before. If there is no result the python script shall do something different, e. g. printing a message.
I tried to compare the statementresult with None (but its an object, even if its empty), or use the first index. I looked for a solution in the documentation and online but could not find anything. How can I check if its empty or not? Is it also possible to get e. g. the 3rd result if it exists?
Thanks!
Stefan
I found a way using the internal method peek() of class StatementResult. If you call this method it will raise an error in case there no records in the result object. I wrapped this code within a function which can be used passing the Result object to it.
def isResultRecord(results):
try:
results.peek()
except ResultError:
return False
else:
return True
if (results.peek() is None):
# empty object
I am currently testing one of my classes which sets variables with the help of pygeoip.
org_by_addr returns None when there is nothing found in the database:
seek_org = self._seek_country(ipnum)
if seek_org == self._databaseSegments:
return None
While the country_name_by_addr function returns an empty string.
This forces me to check if the return is None and then setting it to '' to have the variables uniformly.
Does anybody know, what the reason is to give different returns when there is no entry in the database?
Other than the obvious "variable uniformity", what is the point of changing the NoneType to an empty string? There is a reason why
bool ('') == bool (None) == False
In my opinion this is a stylistic difference. However, when a package has different return types like this, it can hint several things:
-if the function returns None, you can probably guess that the function would return an instanced object if a match was found in the database.
-if instead of returning None, the function returns an empty string, you can at least expect the output of that function to return a valid string when an entry is found in the database.
-if the function returns 0 instead of None, you can probably guess that the function would return a number of some sort if an entry was found in the database
So really it's mostly about informing the user in some way about what a valid return type would be.
My final suggestion would be to do away with the traditional thought of "types" when using Python. By that I mean the C philosophy of typing. In python there is a reason that you can say:
if result:
#some code
And have it be valid across several different "types".
The question is in the title...
I'm in a process of learning Python and I've heard a couple of times that function returning None is something you never should have in a real program (unless your function never returns anything). While I can't seem to find a situation when it is absolutely necessary, I wonder if it ever could be a good programming practice to do it. I.e., if your function returns integers (say, solutions to an equation), None would indicate that there is no answer to return. Or should it always be handled as an exception inside the function? Maybe there are some other examples when it is actually useful? Or should I never do it?
This just flat-out isn't true. For one, any function that doesn't need to return a value will return None.
Beyond that, generally, keeping your output consistent makes things easier, but do what makes sense for the function. In some cases, returning None is logical.
If something goes wrong, yes, you should throw an exception as opposed to returning None.
Unfortunately, programming tends to be full of advice where things are over-generalized. It's easy to do, but Python is pretty good with this - practicality beats purity is part of the Zen of Python. It's essentially the use case for dict.get() - in general, it's better to throw the exception if a key isn't found, but in some specific cases, getting a default value back is more useful.
def abc():
print 1
return None
print 2
is the same as
def abc():
print 1
return
print 2
or even
def abc():
print 1
All functions that don't return something return None. One very important use case of returning None is when you want to say "terminate this function" without having to nest a bunch of ifs.
It's a little complicated.
It comes down to cases here:
A function that merely mutates its object's state doesn't return anything (returns None). For example, given a list called L: L.sort(); L.append("joe")
Other functions create a new object or a new copy of an object, and return it without mutating the original list. Consider: sorted(L) ; y = L + [1,2,3]
It's generally bad form to return None meaning "everything is fine."
If you have some kind of lookup/accessor, None means "the value of that item is None", and when it's not found you should throw the appropriate exception.
In most other cases, returning None is a little confusing.
I have a function that treats and returns data, but according to a boolean input parameter, should do a slightly different treatment (not different enough to justify a new function, I think). This slightly different treatment also requires the returning of an additional parameter.
Let's say I have this.
def func(data, special_case = False):
#Do treatment
...
if special_case:
#do some more stuff
...
#return results
if special_case:
return results, extra_results
else:
return results
Is that considered clean? Or maybe I should always return the second variable, but just make it empty when I'm not treating the special case?
#return results
if special_case:
extra_results = something
else:
extra_results = []
return results, extra_results
No, I don't think so. Now your caller has to know about your function internals, specifically that your option changes the return type. That's just another thing for the caller to remember, and is poor encapsulation.
I would either split this into two functions (preferred), or return a None placeholder, or return an object that can be introspected for additional elements. But the structure of the returned data type should not change.
Yes, you should always return the same data type.
How about a dictionary, where one of the keys always contain a value and the second is either None or the special case value:
return { 'first_var':results,
'special_var': extra_results if extra_results else None}
Is it possible to declare a variable in Python, like so?:
var
so that it initialized to None? It seems like Python allows this, but as soon as you access it, it crashes. Is this possible? If not, why?
EDIT: I want to do this for cases like this:
value
for index in sequence:
if value == None and conditionMet:
value = index
break
Related Questions
Why can a function modify some arguments as perceived by the caller, but not others?
Python Variable Declaration
See Also
Python Names and Values
Other languages have "variables"
Why not just do this:
var = None
Python is dynamic, so you don't need to declare things; they exist automatically in the first scope where they're assigned. So, all you need is a regular old assignment statement as above.
This is nice, because you'll never end up with an uninitialized variable. But be careful -- this doesn't mean that you won't end up with incorrectly initialized variables. If you init something to None, make sure that's what you really want, and assign something more meaningful if you can.
In Python 3.6+ you could use Variable Annotations for this:
https://www.python.org/dev/peps/pep-0526/#abstract
PEP 484 introduced type hints, a.k.a. type annotations. While its main focus was function annotations, it also introduced the notion of type comments to annotate variables:
# 'captain' is a string (Note: initial value is a problem)
captain = ... # type: str
PEP 526 aims at adding syntax to Python for annotating the types of variables (including class variables and instance variables), instead of expressing them through comments:
captain: str # Note: no initial value!
It seems to be more directly in line with what you were asking "Is it possible only to declare a variable without assigning any value in Python?"
Note: The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc.
I'd heartily recommend that you read Other languages have "variables" (I added it as a related link) – in two minutes you'll know that Python has "names", not "variables".
val = None
# ...
if val is None:
val = any_object
I'm not sure what you're trying to do. Python is a very dynamic language; you don't usually need to declare variables until you're actually going to assign to or use them. I think what you want to do is just
foo = None
which will assign the value None to the variable foo.
EDIT: What you really seem to want to do is just this:
#note how I don't do *anything* with value here
#we can just start using it right inside the loop
for index in sequence:
if conditionMet:
value = index
break
try:
doSomething(value)
except NameError:
print "Didn't find anything"
It's a little difficult to tell if that's really the right style to use from such a short code example, but it is a more "Pythonic" way to work.
EDIT: below is comment by JFS (posted here to show the code)
Unrelated to the OP's question but the above code can be rewritten as:
for item in sequence:
if some_condition(item):
found = True
break
else: # no break or len(sequence) == 0
found = False
if found:
do_something(item)
NOTE: if some_condition() raises an exception then found is unbound.
NOTE: if len(sequence) == 0 then item is unbound.
The above code is not advisable. Its purpose is to illustrate how local variables work, namely whether "variable" is "defined" could be determined only at runtime in this case.
Preferable way:
for item in sequence:
if some_condition(item):
do_something(item)
break
Or
found = False
for item in sequence:
if some_condition(item):
found = True
break
if found:
do_something(item)
Well, if you want to check if a variable is defined or not then why not check if its in the locals() or globals() arrays? Your code rewritten:
for index in sequence:
if 'value' not in globals() and conditionMet:
value = index
break
If it's a local variable you are looking for then replace globals() with locals().
I usually initialize the variable to something that denotes the type like
var = ""
or
var = 0
If it is going to be an object then don't initialize it until you instantiate it:
var = Var()
First of all, my response to the question you've originally asked
Q: How do I discover if a variable is defined at a point in my code?
A: Read up in the source file until you see a line where that variable is defined.
But further, you've given a code example that there are various permutations of that are quite pythonic. You're after a way to scan a sequence for elements that match a condition, so here are some solutions:
def findFirstMatch(sequence):
for value in sequence:
if matchCondition(value):
return value
raise LookupError("Could not find match in sequence")
Clearly in this example you could replace the raise with a return None depending on what you wanted to achieve.
If you wanted everything that matched the condition you could do this:
def findAllMatches(sequence):
matches = []
for value in sequence:
if matchCondition(value):
matches.append(value)
return matches
There is another way of doing this with yield that I won't bother showing you, because it's quite complicated in the way that it works.
Further, there is a one line way of achieving this:
all_matches = [value for value in sequence if matchCondition(value)]
If I'm understanding your example right, you don't need to refer to 'value' in the if statement anyway. You're breaking out of the loop as soon as it could be set to anything.
value = None
for index in sequence:
doSomethingHere
if conditionMet:
value = index
break
I know it's coming late but with python3, you can declare an uninitialized value by using
uninitialized_value:str
# some code logic
uninitialized_value = "Value"
But be very careful with this trick tho, because
uninitialized_value:str
# some code logic
# WILL NOT WORK
uninitialized_value += "Extra value\n"
If None is a valid data value then you need to the variable another way. You could use:
var = object()
This sentinel is suggested by Nick Coghlan.
Is it possible to declare a variable in Python (var=None):
def decl_var(var=None):
if var is None:
var = []
var.append(1)
return var
You look like you're trying to write C in Python. If you want to find something in a sequence, Python has builtin functions to do that, like
value = sequence.index(blarg)
var_str = str()
var_int = int()
You can trick an interpreter with this ugly oneliner if None: var = None
It do nothing else but adding a variable var to local variable dictionary, not initializing it. Interpreter will throw the UnboundLocalError exception if you try to use this variable in a function afterwards. This would works for very ancient python versions too. Not simple, nor beautiful, but don't expect much from python.