Related
Consider the following simple code:
import re
def my_match(s):
if re.match("^[a-zA-Z]+", s):
return True
else:
return False
Is there a way to collapse this in a single return statement? In C we could do for example:
return match("^[a-zA-Z]+", s) ? true : false;
Is there something similar in python?
Python also supports this, although the syntaxes is a little different than most languages.
import re
def my_match(s):
return True if re.match("^[a-zA-Z]+", s) else False
In general, the Python syntax is val_when_true if cond else val_when_false, compared to the cond ? val_when_true : val_when_false you see in other languages.
In your particular case though, you can just write:
import re
def my_match(s):
return bool(re.match("^[a-zA-Z]+", s))
A more generell solution would be to use the following code line. It excludes a fit with length 0 as it specificly checks for the None statement. In this case an empty string is impossible but it is more explicit.
return re.match("^[a-zA-Z]+", s) is not None
re.match() returns a value that can be evaluated for truthiness. So if you don't need to return the exact values True and False, you can just directly return the result of the match() function:
def my_match(s):
return re.match("^[a-zA-Z]+", s)
And then the caller can say:
if my_match(x):
...
else:
...
Although in this specific case, my_match() becomes a mostly useless wrapper function, and you could just call re.match(...) directly.
if re.match(...):
...
else:
...
The other answers show the ternary equivalent in Python. But since Python also assigns truthiness to values and expressions, you could simply use:
my_match = lambda s : bool(re.match("^[a-zA-Z]+", s))
There isn't any reason in particular that I wish to do this, I just wanted to see False be True every once in a while.
import random
def dice():
return random.randint(1,3)==2
False = dice()
This will not give me what I want--I imagine False being initialized to some value as dice() is called, and thus remaining as that value thereon. How can I make it so that each time I check the value of False, it is as if I have called dice()?
If anyone has a better way to phrase this please feel free to provide an edit. Thanks.
To do this, you need more control over the name lookup procedure than Python ordinarily gives you. You need to execute the code in a namespace that uses name lookup rules you control, which means you have to use exec:
import random
class WeirdLocals(dict):
def __getitem__(self, index):
if index == 'False':
return random.choice([True, False])
return super(WeirdLocals, self).__getitem__(index)
exec '''
print False # Might print True
print False # Might print True
print False # Might print True
''' in globals(), WeirdLocals()
Note that functions defined inside an exec will ignore the provided locals for name lookup, and even if you try to provide a global dict with a weird __getitem__ override, they might bypass it anyway.
You cannot do that in either Python 2 or 3. You can assign a value to False in Python 2, but what you can't do is make it so that just reading the value of a plain variable (False or anything else) calls a function.
You can do it if the thing you're reading is not a bare-name variable but some kind of expression (like an attribute access). That is, you can make it so that something like a.b evaluates to a different value every time, but not so that just plain a evaluates to a different value every time.
If you can tolerate having to use . in your variable name, the #property decorator can give you want you want.
Example:
import random
class Foo:
def __init__(self):
pass
#property
def True(self):
return random.choice([True,False,True])
And then if you do
F=Foo()
print(F.True) #will return True 66% of the time and False 33% of
the time.
You can't do that with just False; if you're calling a function, you need to use the function syntax. You could do
False = dice
...
if my_value == False():
... action
I'd like to see if it's possible to run through a list of functions in a function. The closest thing I could find is looping through an entire module. I only want to use a pre-selected list of functions.
Here's my original problem:
Given a string, check each letter to see if any of the 5 tests fulfill.
If a minimum of 1 letter passes a check, return True.
If all letters in the string fails the check, return False.
For each letter in the string, we will check these functions: isalnum(), isalpha(), isdigit(), islower(), isupper()
The result of each test should print to different lines.
Sample Input
qA2
Sample Output (must print to separate lines, True if at least one letter passes, or false is all letters fail each test):
True
True
True
True
True
I wrote this for one test. Of course I could just write 5 different sets of code but that seems ugly. Then I started wondering if I could just loop through all the tests they're asking for.
Code for just one test:
raw = 'asdfaa3fa'
counter = 0
for i in xrange(len(raw)):
if raw[i].isdigit() == True: ## This line is where I'd loop in diff func's
counter = 1
print True
break
if counter == 0:
print False
My fail attempt to run a loop with all the tests:
raw = 'asdfaa3fa'
lst = [raw[i].isalnum(),raw[i].isalpha(),raw[i].isdigit(),raw[i].islower(),raw[i].isupper()]
counter = 0
for f in range(0,5):
for i in xrange(len(raw)):
if lst[f] == True: ## loop through f, which then loops through i
print lst[f]
counter = 1
print True
break
if counter == 0:
print False
So how do I fix this code to fulfill all the rules up there?
Using info from all the comments - this code fulfills the rules stated above, looping through each method dynamically as well.
raw = 'ABC'
functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]
for func in functions:
print any(func(letter) for letter in raw)
getattr approach (I think this is called introspection method?)
raw = 'ABC'
meths = ['isalnum', 'isalpha', 'isdigit', 'islower', 'isupper']
for m in meths:
print any(getattr(c,m)() for c in raw)
List comprehension approach:
from __future__ import print_function ## Changing to Python 3 to use print in list comp
raw = 'ABC'
functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]
solution = [print(func(raw)) for func in functions]
The way you are looping through a list of functions is slightly off. This would be a valid way to do it. The functions you need to store in the list are the generic string functions given by str.funcname. Once you have those list of functions, you can loop through them using a for loop, and just treat it like a normal function!
raw = 'asdfaa3fa'
functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] # list of functions
for fn in functions: # iterate over list of functions, where the current function in the list is referred to as fn
for ch in raw: # for each character in the string raw
if fn(ch):
print(True)
break
Sample outputs:
Input Output
===================================
"qA2" -----> True True True True True
"asdfaa3fa" -----> True True True True
Also I notice you seem to use indexing for iteration which makes me feel like you might be coming from a language like C/C++. The for in loop construct is really powerful in python so I would read up on it (y).
Above is a more pythonic way to do this but just as a learning tool, I wrote a working version that matches how you tried to do it as much as possible to show you where you went wrong specifically. Here it is with comments:
raw = 'asdfaa3fa'
lst = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] # notice youre treating the functions just like variables and aren't actually calling them. That is, you're writing str.isalpha instead of str.isalpha()
for f in range(0,5):
counter = 0
for i in xrange(len(raw)):
if lst[f](raw[i]) == True: # In your attempt, you were checking if lst[f]==True; lst[f] is a function so you are checking if a function == True. Instead, you need to pass an argument to lst[f](), in this case the ith character of raw, and check whether what that function evaluates to is true
print lst[f]
counter = 1
print True
break
if counter == 0:
print False
Okay, so the first question is easy enough. The simple way to do it is just do
def foo(raw):
for c in raw:
if c.isalpha(): return True
if c.isdigit(): return True
# the other cases
return False
Never neglect the simplest thing that could work.
Now, if you want to do it dynamically -- which is the magic keyword you probably needed, you want to apply something like this (cribbed from another question):
meths = [isalnum, isalpha, isdigit, islower, isupper]
for c in raw:
for m in meths:
getattr(c, m)()
Warning, this is untested code meant to give you the idea. The key notion here is that the methods of an object are attributes just like anything else, so, for example getattr("a", "isalpha")() does the following:
Uses getattr to search the attributes dictionary of "a" for a method named isalpha
Returns that method itself -- <function isalpha>
then invokes that method using the () which is the function application operator in Python.
See this example:
In [11]: getattr('a', 'isalpha')()
Out[11]: True
All the other answers are correct, but since you're a beginner, I want to point out the problem in your code:
lst = [raw[i].isalnum(),raw[i].isalpha(),raw[i].isdigit(),raw[i].islower(),raw[i].isupper()]
First: Not sure which value i currently has in your code snipped, but it seems to point somewhere in the string - which results in single characters being evaluated, not the whole string raw.
Second: When you build your list, you are already calling the methods you want to insert, which has the effect that not the functions themself get inserted, but their return values (that's why you're seeing all those True values in your print statement).
Try changing your code as follows:
lst = [raw.isalnum, raw.isalpha, raw.isdigit, raw.islower, raw.isupper]
I'm going to guess that you're validating password complexity, and I'm also going to say that software which takes an input and says "False" and there's no indication why is user-hostile, so the most important thing is not "how to loop over nested char function code wizardry (*)" but "give good feedback", and suggest something more like:
raw = 'asdfaa3fa'
import re
def validate_password(password):
""" This function takes a password string, and validates it
against the complexity requirements from {wherever}
and returns True if it's complex enough, otherwise False """
if not re.search('\d', password):
print("Error: password needs to include at least one number")
return False
elif not re.search('[a-z]', password):
print("Error: password must include at least one lowercase letter")
return False
elif not re.search('[A-Z]', password):
print("Error: password must include at least one uppercase letter")
return False
print("Password is OK")
return True
validate_password(raw)
Try online at repl.it
And the regex searching checks ranges of characters and digits in one call, which is neater than a loop over characters.
(PS. your functions overlap; a string which has characters matching 'isupper', 'islower' and 'isnumeric' already has 'isadigit' and 'isalnum' covered. More interesting would be to handle characters like ! which are not upper, lower, digits or alnum).
(*) function wizardry like the other answers is normally exactly what I would answer, but there's so much of that already answered that I may as well answer the other way instead :P
To answer the original question:
raw = 'asdfa3fa'
functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]
isanything = [func(raw) for func in functions]
print repr(isanything)
Since you are looping through a list of simple items and trying to find if all of the functions has any valid results, you can simply define the list of functions you want to call on the input and return that. Here is a rather pythonic example of what you are trying to achieve:
def checker(checks, value):
return all(any(check(r) for r in value) for check in checks)
Test it out:
>>> def checker(checks, value):
... return all(any(check(r) for r in value) for check in checks)
...
>>> checks = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]
>>> checker(checks, 'abcdef123ABC')
True
>>> checker(checks, 'abcdef123')
False
>>>
You can use introspection to loop through all of an object's attributes, whether they be functions or some other type.
However you probably don't want to do that here, because str has lots of function attributes, and you're only interested in five of them. It's probably better to do as you did and just make a list of the five you want.
Also, you don't need to loop over each character of the string if you don't want to; those functions already look at the whole string.
Check out this one-line solution for your problem. That problem is from HackerRank. I loop through a list of functions using the built-in getattr function.
s='qA2'
[print(bool(list(filter(lambda x : getattr(x, func)(),s)))) for func in ['isalnum','isalpha','isdigit','islower','isupper']]
This is a homework problem. I've been trying to solve it but couldn't get the right result.
This is the question:
Write a function string2int that attempts to convert a string to an integer. If the string does represent a positive integer then that integer should be returned. If the string does not represent a positive integer then you should raise a syntax exception (raise SyntaxError('not an integer')).
You may choose to use the (already defined) function all_digits that takes a string and returns True if all the characters of the string are digits and False otherwise.
What I've got so far is:
try all_digits is True:
return int(num)
except all_digits is False:
raise SyntaxError('not an integer')
Because I'm using an already defined function, I didn't define a function (or did I get it wrong?).
Can anyone have a look at my code please? Much appreciated.
I can guess, but you might want to tell us what kind of error you get when you execute the code (just a heads up for the next time you ask a question).
There's a couple of mistakes:
1) The syntax of
try all_digits is True:
is wrong. The "try" statement should look like this:
try:
<your code>
except <type of exception to catch>:
<error handling code>
2) You said "all_digits" is a function. Therefore, the code
all_digits is True
should be
if all_digits(num):
Putting it all together:
def string2int(num):
if all_digits(num):
return int(num)
raise SyntaxError('not an integer')
In addition to Rawing's excellent answer, note that the usual time to use try/except is when you can handle the error thrown in the try block and continue as usual. For instance:
def add_three(x) -> int:
try:
return x + 3
except TypeError:
# someone passed a non-int/float to the function!
# let's try and coerce it.
return int(x) + 3
# if this still throws an exception, we'll let it
# raise its own TypeError exception!
In your case it looks like you're just doing regular conditionals, so use if all_digits(num): return int(num) else: raise TypeError('not an integer')
all_digits(string) function:
First, it's good to understand what does the pre-defined all_digits(string) function do. Following is a sample implementation of that function, which works as desired by your description. It checks whether each letter of the string is a digit and returns a boolean, True or False, accordingly:
def all_digits(string):
''' only returns True if all characters of the string are Integers '''
for l in string:
if l.isdigit(): pass
else: return False
return True
string2num(string) function with raise statement:
Now, we can use this function in our error handling block of the string2num(string) function. Since your problem requires you to only raise a specific exception and not to continue with an alternate block of code, you do not need the try: ... except: block.
With the proper syntax of the raise statement, we can write:
def string2num( string = '-23'):
if all_digits(string):
return int('23')
raise SyntaxError("not an integer")
and we get:
>>> string2num()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in string2num
SyntaxError: not an integer
with try: ... except: ... block:
But if you do want to execute an alternate block of code when the exception is raised, you can use the try: ... except: block syntax. You may need it, for instance, if you want to further check if the string is a negative integer and if so then return the negative integer:
def string2num( string = '-23'):
try:
if all_digits(string):
return int(string)
raise SyntaxError("not an integer")
except SyntaxError:
#alternate code goes here#
try:
return int(string)
except ValueError:
print "string contains an alphabet"
This will produce:
>>> string2num()
-23
>>> string2num('ab2')
string contains an alphabet
Style for if statement:
As a side note on your style, you don't have to explicitly write whether an expression evaluates to True or False in an if statement, like so:
if all_digits(string) is True:
Since all_digits(string) returns a boolean, you can equivalently just say if True, like so:
if all_digits(string):
I'm working through a Python 3 book and came across the string function isidentifier(). The text description is "s.isidentifier() : Returns True if s is non empty and is a valid identifier". I tested it in the Python Shell like this:
>>> s = 'test'
>>> s.isidentifier()
True
>>> 'blah'.isidentifier()
True
I would expect the 2nd statement to return false since 'blah' is not held in a variable. Can anyone explain this? Thanks.
Returns True if s is non empty and is a valid identifier.
What they mean is that s could be valid as an identifier. It doesn't imply that it is an identifier that's in use.
Your first example is showing the same thing: 'test' (what isidentifier is actually checking) is not the name of a variable either. I think you meant
>>> 's'.isidentifier()
True
"isidentifier" doesn't say anything about the "variable" the string being tested is referenced by. So
'blah'.isidentifier()
is identical to
s = 'blah'
s.isidentifier()
In Python, it's never (or rarely) about the "variable" (Python doesn't have variables), it's about the object. In this case, strings.
Python doesn't have "variables". It is more helpful to think in terms of objects.
'blah' definitely exists at the time 'blah'.isidentifier() is called (after all it means that "call isidentifier() method of the string object 'blah'").
So if your understanding were correct, isidentifier() method of string objects should always return True, because at the time of the call, the object definitely exists.
What isidentifier() does is to check that the string object can be used as a valid identifier. Try these two lines in your Python session for example:
>>> a = "$"
>>> "$".isidentifier()
Even though "$" is assigned to the name a, the isidentifier() call returns False since $ is not a valid identifier in Python.
isidentifier is a Python function that simply tests whether a string contains only certain characters (underscore, digits, and alphas) and starts with an alpha or an underscore, so the string can be used for a valid Python identifier. Other functions that test for character classes are isalpha, isalnum, isdigit, and others.
ss = (
'varABC123',
'123ABCvar',
'_123ABCvar',
'var_ABC_123',
'var-ABC-123',
'var.ABC.123',
# check your own strings
)
fmt = '%-15s%-10s%-10s%-10s%-10s'
print(fmt % ('', 'isalpha', 'isalnum', 'isdigit', 'isidentifier'))
for s in ss:
print(fmt % (s, s.isalpha(), s.isalnum(), s.isdigit(), s.isidentifier()))
Result:
isalpha isalnum isdigit isidentifier
varABC123 False True False True
123ABCvar False True False False
_123ABCvar False False False True
var_ABC_123 False False False True
var-ABC-123 False False False False
var.ABC.123 False False False False