Using "and" in return - python

I'm taking Web Application Engineering course on Udacity. I noticed that the instructor use and operator in return statement in his validation method. And I didn't understand how it is possible to return 2 arguments. I think, it may be something like if statement. Could anyone explain what it actually is?
Here is the validation method:
USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
def valid_username(username):
return username and USER_RE.match(username)
Thanks in advance.

The and operator evaluates whether both of its arguments are tru-ish, but in a slightly surprising way: First it examines its left argument. If it is truish, then it returns its right argument. If the left argument is falsish, then it returns the left argument.
So the last line in your code:
return username and USER_RE.match(username)
is the same as:
if username:
return USER_RE.match(username)
else:
return username
Strings like username are truish if they are not empty. The regex match function returns a truish match object if the pattern matches, and returns None, a falsish value, if it doesn't match.
The net result is that valid_username will return a truish value if username is not an empty string, and the username matches the given pattern.
Note the "and" here has nothing to do with returning two values, it's computing one value.

When you use a logical operator, it continues according to the rules, so with and, it evaluates the truthiness of the first statement and if it isn't truthy, it returns a non-truthy value (in the first case, '').
print repr("" and "THIS IS POST AND")
""
print "" or "THIS IS POST AND"
THIS IS POST AND
print None or "Something else"
Something else
Where this comes in handy is when you don't want to call a non-existent method on something like None (e.g. the length trait):
r = None
s = [1,2,3,4]
print r and len(r)
None
print s and len(s)
4
In the case you posted, the point is that you only want to check the username against the regular expression if the username is truthy.
It's important to note here that and, and or both short-circuit. So if you get something non-truthy, the function won't even evaluate the regular expression.

and is just a binary operator. return a and b is structurally the same as return a + b or return a * b, and works the same way. The expression is evaluated, then its result is given to return, which returns it to the caller. There is nothing at all special about using and in a return statement.
As explained very well by Ned's answer, the result of a and b is true-ish if both of a and b are true-ish, and false-ish otherwise. It also short-circuits if the left argument is false-ish, since that is sufficient to determine the result of the whole a and b expression.
In this case, an empty string would not match that regular expression, so the operation is redundant considered purely as logic. I strongly suspect though that it's being used here because username might be given the value None, which would cause the regular expression match to throw an exception. Using username and USER_RE.match(username) rather than just USER_RE.match(username) means that any false-ish value (including None) for username causes the function to return something false-ish without even attempting the regular-expression match.
But again, this has nothing to do with return, it's just how and works.

Related

Python returns generator object without yield

I am trying to generate a function which tells me if a word is an isogram (contains duplicate values). However, this code always returns a generator object.
def is_isogram(string):
return (True if (string.lower().count(letter) == 1) else False for letter in string.lower())
I know how to solve the problem, I was just wondering what is wrong with my code.
I suppose your function is intended to return a boolean, but the return statement has an iteration happening, where each value is mapped to a boolean. The parentheses give you an iterator over those booleans. The function's description suggests that the function should return True when the input has duplicate letters, but the mapping gives True when a letter is not duplicate. So you have three problems:
The iterator
The multiple booleans, when you want one boolean
The booleans indicate the inverse of what you want to return
So your idea for an algorithm should be changed to this:
def is_isogram(string):
return any(letter for letter in string.lower() if string.lower().count(letter) > 1)
Side note: this algorithm is not efficient. More efficient is to create a set:
def is_isogram(string):
return len(set(string.lower())) < len(string)
By wrapping your returned value into parenthesis you've created a generator expression, check https://peps.python.org/pep-0289/ for details.

How to evaluate string as boolean in return statement?

I have a function like this in Python 3.4:
def is_value_valid(the_str):
return len(the_str) != 0
There are of course other ways to write this, such as return the_str != "". Are there more pythonic ways of writing this expression? I am familiar with the concepts of truthy/falsy, so I know I could shortcut this in an if condition:
if not the_str:
# do stuff
But the if expects a boolean result in its expression (this is my naive oversimplification here as a C++ programmer; I'm not familiar with standardese for this). However, there is nothing there to force the expression to evaluate to boolean in the return statement. I have tried just returning the string, and as long as no one treats the returned value as a string, it works just fine in calling code under boolean context. But from a post-condition perspective, I don't want to return a non-boolean type.
This is exactly what the bool() function does; return a boolean based on evaluating the truth value of the argument, just like an if statement would:
return bool(the_str)
Note that if doesn't expect a boolean value. It simply evaluates the truth value of the result of the expression.
>>> bool("foo")
True
>>> bool("")
False
Empty strings evaluate to False, but everything else evaluates to True. So this should not be used for any kind of parsing purposes.
So just return bool(the_str) in your case.
The if statement automatically evaluates a string as a boolean. However, if you want to return your string as a boolean you would simply do
return bool(the_str)
bool(the_str) is definitely the way to go, as several have mentioned.
But if your method requires that a string be given, I would also test for the string actually being a string (because bool(5) and bool("this is a string") will both return true.
return isinstance(the_str, str) and bool(the_str)
Or when used in an if statement:
if isinstance(the_str, str) and the_str:
# here we are sure it's a string whose length > 0
def is_value_valid(the_str):
return bool(len(the_str) != 0)
Using bool(x) converts the value to a boolean. This function takes len(the_str) != 0, evaluates it, converts it to bool, then returns the value.
The bool(x) is not required, you can just have the parentheses, because it will already return a bool, as evaluations return boolean by default.

Strange python syntax, or in print statement

I can't find anything about this, so I'm forced to ask here. I'm sure it's an easy question for anybody who knows python well.
python 2:
print raw_input() == 0 or hash(tuple(map(int, raw_input().split(' '))))
python 3:
print(input()==0 or hash(tuple(map(int,input().strip().split()))))
I am trying to understand why an 'or' is in a print statement.
The code in question has a boolean operator inside a print statement, comparing a boolean and an int. This is what I need explained to me. It is obviously specific to python. What would the code print in the case that input()==0 returns true? How can we compare a boolean and a hash, and again, what are we doing making boolean comparisons inside a print statement?
In Python, comparisons with or or and make use of two features:
Truthy and falsey values, and
Short-circuiting.
So, when you have something like this:
print(input()==0 or hash(tuple(map(int,input().strip().split()))))
It'll follow the order of operations, checking whether input() returns a 0. Since it's that or the next term, if it's true then the next term has no impact on the result and won't be evaluated. If that happens, it'll print True, since that's what's returned by input()==0.
If that's false, it'll evaluate the next part, getting input, mapping it as an integer, turning it into a tuple, and hashing it. It'll then return that hash whether or not it's a truthy value (a number other than 0, a sequence or set with contents, etc.).
Python will first evaluate whether or not input()==0 is True. If it is, then Python will print it and ignore the rest of the line. If the input is not equal to 0 and this evaluates as False, then it will be ignored and the rest of the line will be printed regardless of how it evaluates. So even if the rest of the line would evaluate as False, Python will print its result.
A clearer example would be setting the name of something based on user input and requiring a default value.
name = raw_input("What is your name?")
print ("So your name is...")
print (name or "John Smith")
name will be evaluated as True or False. Since an empty string will be considered False, if the user enters nothing then instead Python will print the default name after the or operator.
I am guessing that your code is Python3, since otherwise it is unlikely that the result of input() would have a strip method.
Here is a long form of the code, with explanations.
# Read a line of input. Returns a string.
a = input()
# Compare to integer 0, always False.
# Effectively, this ignores the first line of input.
b = a == 0
# Separate function to represent lazy evaluation.
def y():
# Get a second line of input, as a string.
c = input()
# Strip leading and trailing whitespace, still a string.
# This line is useless since split() with no argument does this.
d = c.strip()
# Split the line by any runs of whitespace. Returns a list of strings.
e = d.split()
# For each string in the list, convert it to an integer in base 10.
# Return an iterator (not list) of ints.
# Most people would write (int(s) for x in e) for a generator
# comprehension, or [int(s) for x in e] for a list comprehension.
m = map(int, e)
# Consume the iterator into a tuple of ints.
# Note that it can't be a list, because lists aren't hashable.
t = tuple(m)
# Hash the tuple, returning a single int.
return hash(t)
# If b is truthy, set x to it. Otherwise, evaluate y() and set x to that.
# Unlike many languages, the arguments to or are *not* coerced to bool.
# Since b is False, y() will be evaluated.
x = b or y()
# Print the result of y().
# i.e. the hash of the tuple of ints on the second line.
# This is essentially a meaningless number.
print(x)

Are these two python statements the same?

I have these two statements
return self.getData() if self.getData() else ''
and
return self.getData() or ''
I want to know are they same or there is any difference
I would say No because if self.getData() changes something during its operation, then the first statement has the possibility of returning a different result since it will make a 2nd call to it.
Maybe, but only if self.getData() is a pure function and has no side effects. More importantly the object that self.getData() returns must also be free of any side effects and consistently return a boolean value.
In the simplest case if f() is defined as:
def f():
return ["Hello World!"]
Then the following:
x = f() if f() else ""
is logically equivalent to:
x = f() or ""
Since f() is treated as a boolean expression in both cases and f() will evaluate to a True(ish) or False(ly) value both expressions will return the same result.
This is called Logical Equivalence
In logic, statements p and q are logically equivalent if they have the
same logical content. This is a semantic concept; two statements are
equivalent if they have the same truth value in every model (Mendelson
1979:56). The logical equivalence of p and q is sometimes expressed as
p \equiv q, Epq, or p \Leftrightarrow q. However, these symbols are
also used for material equivalence; the proper interpretation depends
on the context. Logical equivalence is different from material
equivalence, although the two concepts are closely related.
They will have the same result, since both treat self.getData()'s result in a boolean context, but beware:
1)
return self.getData() if self.getData() else ''
will run the function getData twice, while
2)
return self.getData() or ''
will only run it once. This can be important if getData() takes a while to execute, and it means that 1) is not the same as 2) if the function getData() has any side effects.
Stick with 2).
The only difference I see is that the first one will call self.getData() twice, with the first one being used to evaluate boolean value and the second may be returned(if the first evaluated to True).
The other option will evaluate the function only once, using it both as boolean checking and returning.
This can be crucial if, for example, self.getData() deletes or modifies the data after returning it or the function takes long to compute.

using exception with for loop in python

hey guys am new to python app development..i have been trying to fetch only numbers from a list using a for loop..But am confused with the correct syntax..The code i have been used.is like below.
babe = [10,11,13,'vv']
int(honey) [for honey in babe]:
print honey
When i run this i got syntax error.i have tried many situations.But it didnt helped me at all.Sorry for the silly question..
do i wanna add square brackets or something on the second line ??
Am really stuck.Hope you guys can help me out..Thanks in advance
You seem to be conflating the syntax for for loops (a statement followed by a suite of statements ... otherwise known as a "block of code") and a list comprehension (an expression).
Here's a list comprehension:
#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = [int(x) for x in b]
... that's syntactically valid. However, the semantics of that example will raise an exception because 'vv' is not a valid literal (string). It cannot be interpreted as a decimal integer.
Here's a for loop:
#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = list()
for x in b:
try:
a.append(int(x))
except ValueError:
pass
In this case we explicitly loop over the given list (b) and ignore any ValueError exceptions raised when we try to convert each of those entries into an integer.
There is no reasonable way to handle exceptions from within a list comprehension. You could write a function which returned some sentinel value (from the expression) for any invalid input value. That would look something like this:
#/usr/bin/python
# Given:
b = [1, 2, 3, 'vv']
def mk_integer_if_possible(n):
'''Returns an integer or the sentinel value None
'''
results = None
try:
results = int(n)
except ValueError:
pass
return results
# Use that function:
a = [mk_integer_if_possible(x) for x in b if mk_integer_if_possible(x) is not None]
Note: the absurd function name is deliberate. This is an ugly way to do this and the awkwardness of having to call this putative function TWICE for each element of b is an indication that you should NOT use a list comprehension for this situation. (You have to call it once to make the conversion but again for the conditional. Saving the results from one call would, of course, be a STATEMENT, which we can't have embedded within an EXPRESSION).
Statements contain one or more expressions. Expressions are components of statements. Python strictly delineates between statements and expressions. Assignments are statements in Python. These distinctions can be nuanced and there are other programming languages where assignments are expressions rather than being strictly defined, by the language's syntax, as statements.
So, use the for loop whenever you have to handle possible exceptions while iterating over any sort of data set and usually when you need to filter on the results generated by mapping a function over a list comprehension.
Incidentally the explicit use of the expression is not None is necessary in this example. If I attempted to shorten that test to simply be if mk_integer_if_possible(x) using Python's implicit boolean handling then we'd be inadvertently filtering out any entries from b that evaluated to integer 0 as well as any that were returned as the None sentinel by my ill-advised function.
In Python it's often fine to use implicit boolean values as conditions. None and False as well as any numerically zero value, any empty string or any sort of empty list, tuple or dictionary, are all treated as "false" in a boolean context. However, when dealing with sentinel values it's best to use the is operator and explicitly test for object identity. Otherwise you'll have corner cases where your condition might be matched by values other than your sentinel.
(Handy trick: if you ever come across the need to allow None through some sort of filter or pass it along, but you need some other sentinel ... just use sentinel = object() ... you can create (instantiate) a generic Pythonobject and use is to match it for your sentinel handling. That will be unique to your code and no other Python object or type will match it. Guaranteed).
By the way ... I should note that this code it technically not "fetching only numbers from a list." It is returning integers for all entries in the list which can be converted thereto. This is a nitpick; but it's a distinction that any good engineer will notice. Do you want to return all integers from the input list? Or do you want to return all entries as integers if that can be so converted? Your code suggested that you're trying to accomplish the latter; so that's how I implemented my working examples for you. However, to implement the later semantics you'd probably want to use either the (mathematical) additive or multiplicative identity property like so:
# ... from within some function:
try:
results = x == x + 0 # Additive identity
except (TypeError, ValueError):
results = None
return results
babe = [10,11,13,'vv']
a = [honey for honey in babe if isinstance(honey, int)]
print a
See more here about list comprehension: https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions

Categories