Related
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']]
im trying to code in python (very new to it) and need to check if an xpath is there then variable = the xpath but if not variable = string.
An example is below
if tree.xpath('//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()') = true
$value = tree.xpath('//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()')
else
$value = ''
You should really start by doing the whole official tutorial before anything else, as it will anwser your question.
First point : Python objects all have a 'truth' value in a boolean context, which is defined by the object's type and actual value. For builtin types, all empty containers (lists, dicts, sets etc), the empty string, all numerical zeros and the None object are false, everything else is true. For non builtin types you'll have to check the package's documentation.
The builtin type bool will also tell you the boolean value of a given object, so all of the below tests are equivalent:
if myobj:
xxx
if bool(myobj):
xxx
if bool(myobj) == True:
xxx
BUT keep in mind that it doesn't imply that bool(myobj) is the same as myobj - the first one is the boolean value of your object, so the following is NOT equivalent (unless myobj is one of True, 1 or 1.0):
if myobj == True:
xxx
Now wrt/ your actual code snippet: it's not valid Python (bad indentation, invalid identifier $value, invalid use of the assignment operator =, missing : after the if and else statements, wrong capitalization for True...)
Assuming you meant:
# let's make this at least readable:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
if tree.xpath(path) == True:
value = tree.xpath(path)
else:
value = ''
The obvious error is the explicit test against True (tree.xpath() doesn't return a boolean). You either have to explicitely cast the return of tree.xpath() to a boolean (which is quite verbose, totally useless and definitly unpythonic) or just let Python do the right thing by removing the == True part of your test.
As a side note: calling tree.xpath twice in a row with the same argument is a waste of processor cycle (both calls will return the same value), so use a variable instead - it will also make your code much more readable and maintainable. The Pythonic version of your code would look something like:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
found = tree.xpath(path)
value = found if found else ''
or even more simply:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
value = tree.xpath(path) or ''
since the or operator will not yield a boolean value but either the first of it's operand that has a true value or the last operand if none has a true value.
#No need to test == if value is bool. and you not check, you assign value with one =
if anything:
#Then do this
else:
#Do this
Assume you have a function, that sometimes returns a value, and sometimes doesn't, because there really is nothing you could return in this case, not even a default value or something. Now you want to do something with the result, but of course only when there is one.
Example:
result = function_call(params)
if result:
print result
Is there a way to write this in a more pythonic way, maybe even in one line?
Like that:
print function_call(params) or #nothing
(Note that I mean it shouldn't print "nothing" or "None". It should actually just not print at all, if the result is None)
No; in Python, name binding is a statement and so cannot be used as an expression within a statement. Since print is also a statement you're going to require 3 lines; in Python 3 you could write:
result = function_call(params)
print(result) if result else None
This isn't quite true for name binding within a comprehension or generator, where name binding is a syntax item that has statement-like semantics:
[print(result) for result in generator_call(params) if result]
As Kos says, you can abuse this to create a one-element comprehension:
[print(result) for result in (function_call(params), ) if result]
Another syntax item that performs name binding and can similarly be abused is the lambda expression:
(lambda result: print(result) if result else None)(function_call(params))
Note that in both these cases the operation on the return value must be an expression and not a statement.
I think the more Pythonic version is actually closer to your original:
result = function_call(params)
if result is not None:
do_something(result)
Checking for is (not) None seems very idiomatic to me - I've used it several times myself and I've also seen it used elsewhere[citation-needed].
From the answers up to now I would do that:
>>> from __future__ import print_function #if Python2.7
>>> def filtered_print(txt):
... txt and print(txt)
...
>>> filtered_print('hello world')
hello world
>>> filtered_print('None')
None
>>> filtered_print(None)
>>>
If someone else has a better solution in mind, I am still open for alternatives, though!
Does Python have something like an empty string variable where you can do:
if myString == string.empty:
Regardless, what's the most elegant way to check for empty string values? I find hard coding "" every time for checking an empty string not as good.
Empty strings are "falsy" (python 2 or python 3 reference), which means they are considered false in a Boolean context, so you can just do this:
if not myString:
This is the preferred way if you know that your variable is a string. If your variable could also be some other type then you should use:
if myString == "":
See the documentation on Truth Value Testing for other values that are false in Boolean contexts.
From PEP 8, in the “Programming Recommendations” section:
For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
So you should use:
if not some_string:
or:
if some_string:
Just to clarify, sequences are evaluated to False or True in a Boolean context if they are empty or not. They are not equal to False or True.
The most elegant way would probably be to simply check if its true or falsy, e.g.:
if not my_string:
However, you may want to strip white space because:
>>> bool("")
False
>>> bool(" ")
True
>>> bool(" ".strip())
False
You should probably be a bit more explicit in this however, unless you know for sure that this string has passed some kind of validation and is a string that can be tested this way.
I would test noneness before stripping. Also, I would use the fact that empty strings are False (or Falsy). This approach is similar to Apache's StringUtils.isBlank or Guava's Strings.isNullOrEmpty
This is what I would use to test if a string is either None OR Empty OR Blank:
def isBlank (myString):
return not (myString and myString.strip())
And, the exact opposite to test if a string is not None NOR Empty NOR Blank:
def isNotBlank (myString):
return bool(myString and myString.strip())
I once wrote something similar to Bartek's answer and javascript inspired:
def is_not_blank(s):
return bool(s and not s.isspace())
Test:
print is_not_blank("") # False
print is_not_blank(" ") # False
print is_not_blank("ok") # True
print is_not_blank(None) # False
The only really solid way of doing this is the following:
if "".__eq__(myString):
All other solutions have possible problems and edge cases where the check can fail.
len(myString) == 0 can fail if myString is an object of a class that inherits from str and overrides the __len__() method.
myString == "" and myString.__eq__("") can fail if myString overrides __eq__() and __ne__().
"" == myString also gets fooled if myString overrides __eq__().
myString is "" and "" is myString are equivalent. They will both fail if myString is not actually a string but a subclass of string (both will return False). Also, since they are identity checks, the only reason why they work is because Python uses String Pooling (also called String Internment) which uses the same instance of a string if it is interned (see here: Why does comparing strings using either '==' or 'is' sometimes produce a different result?). And "" is interned from the start in CPython
The big problem with the identity check is that String Internment is (as far as I could find) that it is not standardised which strings are interned. That means, theoretically "" is not necessary interned and that is implementation dependant.
Also, comparing strings using is in general is a pretty evil trap since it will work correctly sometimes, but not at other times, since string pooling follows pretty strange rules.
Relying on the falsyness of a string may not work if the object overrides __bool__().
The only way of doing this that really cannot be fooled is the one mentioned in the beginning: "".__eq__(myString). Since this explicitly calls the __eq__() method of the empty string it cannot be fooled by overriding any methods in myString and solidly works with subclasses of str.
This is not only theoretical work but might actually be relevant in real usage since I have seen frameworks and libraries subclassing str before and using myString is "" might return a wrong output there.
That said, in most cases all of the mentioned solutions will work correctly. This is post is mostly academic work.
Test empty or blank string (shorter way):
if myString.strip():
print("it's not an empty or blank string")
else:
print("it's an empty or blank string")
If you want to differentiate between empty and null strings, I would suggest using if len(string), otherwise, I'd suggest using simply if string as others have said. The caveat about strings full of whitespace still applies though, so don't forget to strip.
if stringname: gives a false when the string is empty. I guess it can't be simpler than this.
I find hardcoding(sic) "" every time for checking an empty string not as good.
Clean code approach
Doing this: foo == "" is very bad practice. "" is a magical value. You should never check against magical values (more commonly known as magical numbers)
What you should do is compare to a descriptive variable name.
Descriptive variable names
One may think that "empty_string" is a descriptive variable name. It isn't.
Before you go and do empty_string = "" and think you have a great variable name to compare to. This is not what "descriptive variable name" means.
A good descriptive variable name is based on its context.
You have to think about what the empty string is.
Where does it come from.
Why is it there.
Why do you need to check for it.
Simple form field example
You are building a form where a user can enter values. You want to check if the user wrote something or not.
A good variable name may be not_filled_in
This makes the code very readable
if formfields.name == not_filled_in:
raise ValueError("We need your name")
Thorough CSV parsing example
You are parsing CSV files and want the empty string to be parsed as None
(Since CSV is entirely text based, it cannot represent None without using predefined keywords)
A good variable name may be CSV_NONE
This makes the code easy to change and adapt if you have a new CSV file that represents None with another string than ""
if csvfield == CSV_NONE:
csvfield = None
There are no questions about if this piece of code is correct. It is pretty clear that it does what it should do.
Compare this to
if csvfield == EMPTY_STRING:
csvfield = None
The first question here is, Why does the empty string deserve special treatment?
This would tell future coders that an empty string should always be considered as None.
This is because it mixes business logic (What CSV value should be None) with code implementation (What are we actually comparing to)
There needs to be a separation of concern between the two.
How about this? Perhaps it's not "the most elegant", but it seems pretty complete and clear:
if (s is None) or (str(s).strip()==""): // STRING s IS "EMPTY"...
if you want to check if a string is completely empty
if not mystring
which works because empty strings are false
but if a string is only whitespace it will be true so you might want to
if not mystring.strip()
Responding to #1290. Sorry, no way to format blocks in comments. The None value is not an empty string in Python, and neither is (spaces). The answer from Andrew Clark is the correct one: if not myString. The answer from #rouble is application-specific and does not answer the OP's question. You will get in trouble if you adopt a peculiar definition of what is a "blank" string. In particular, the standard behavior is that str(None) produces 'None', a non-blank string.
However if you must treat None and (spaces) as "blank" strings, here is a better way:
class weirdstr(str):
def __new__(cls, content):
return str.__new__(cls, content if content is not None else '')
def __nonzero__(self):
return bool(self.strip())
Examples:
>>> normal = weirdstr('word')
>>> print normal, bool(normal)
word True
>>> spaces = weirdstr(' ')
>>> print spaces, bool(spaces)
False
>>> blank = weirdstr('')
>>> print blank, bool(blank)
False
>>> none = weirdstr(None)
>>> print none, bool(none)
False
>>> if not spaces:
... print 'This is a so-called blank string'
...
This is a so-called blank string
Meets the #rouble requirements while not breaking the expected bool behavior of strings.
I did some experimentation with strings like '', ' ', '\n', etc. I want isNotWhitespace to be True if and only if the variable foo is a string with at least one non-whitespace character. I'm using Python 3.6. Here's what I ended up with:
isWhitespace = str is type(foo) and not foo.strip()
isNotWhitespace = str is type(foo) and not not foo.strip()
Wrap this in a method definition if desired.
a = ''
b = ' '
a.isspace() -> False
b.isspace() -> True
The clearest approach is:
if s == "":
Benefits:
Additional indication to the programmer what the type of s should be.
"" is not "hard-coding" a magic value any more than x == 0 is.
Some values are fundamental and do not need a named constant; e.g. x % 2 to check for even numbers.
Cannot incorrectly indicate that any falsy value (e.g. []) is an empty string.
Consider how one checks if an integer is 0:
if x == 0:
One certainly should not do:
if not x:
Both integers and strings are primitive value types. Why treat them differently?
not str(myString)
This expression is True for strings that are empty. Non-empty strings, None and non-string objects will all produce False, with the caveat that objects may override __str__ to thwart this logic by returning a falsy value.
You may have a look at this Assigning empty value or string in Python
This is about comparing strings that are empty. So instead of testing for emptiness with not, you may test is your string is equal to empty string with "" the empty string...
for those who expect a behaviour like the apache StringUtils.isBlank or Guava Strings.isNullOrEmpty :
if mystring and mystring.strip():
print "not blank string"
else:
print "blank string"
When you are reading file by lines and want to determine, which line is empty, make sure you will use .strip(), because there is new line character in "empty" line:
lines = open("my_file.log", "r").readlines()
for line in lines:
if not line.strip():
continue
# your code for non-empty lines
If you are not totally sure, that your input is really a string, I would recommend to use isinstance(object, classinfo) link in addition, as shown in the example.
If not, lists or a True bool value could also be evaluated as True.
<script type="text/javascript" src="//cdn.datacamp.com/dcl-react.js.gz"></script>
<div data-datacamp-exercise data-lang="python">
<code data-type="sample-code">
def test_string(my_string):
if isinstance(my_string, str) and my_string:
print("It's a me, String! -> " + my_string)
else:
print("Nope. No, String")
def not_fully_test_string(my_string):
if my_string:
print("It's a me, String??? -> " + str(my_string))
else:
print("Nope. No, String")
print("Testing String:")
test_string("")
test_string(True)
test_string(["string1", "string2"])
test_string("My String")
test_string(" ")
print("\nTesting String or not?")
not_fully_test_string("")
not_fully_test_string(True)
not_fully_test_string(["string1", "string2"])
not_fully_test_string("My String")
not_fully_test_string(" ")
</code>
</div>
If you just use
not var1
it is not possible to difference a variable which is boolean False from an empty string '':
var1 = ''
not var1
> True
var1 = False
not var1
> True
However, if you add a simple condition to your script, the difference is made:
var1 = False
not var1 and var1 != ''
> True
var1 = ''
not var1 and var1 != ''
> False
In case this is useful to someone, here is a quick function i built out to replace blank strings with N/A's in lists of lists (python 2).
y = [["1","2",""],["1","4",""]]
def replace_blank_strings_in_lists_of_lists(list_of_lists):
new_list = []
for one_list in list_of_lists:
new_one_list = []
for element in one_list:
if element:
new_one_list.append(element)
else:
new_one_list.append("N/A")
new_list.append(new_one_list)
return new_list
x= replace_blank_strings_in_lists_of_lists(y)
print x
This is useful for posting lists of lists to a mysql database that does not accept blanks for certain fields (fields marked as NN in schema. in my case, this was due to a composite primary key).
Below is an elegant solution for any number of spaces.
def str_empty(s: str) -> bool:
"""Strip white space and count remaining characters."""
return len(s.strip()) < 1
>>> str_empty(' ')
True
As prmatta posted above, but with mistake.
def isNoneOrEmptyOrBlankString (myString):
if myString:
if not myString.strip():
return True
else:
return False
return False
I have the variable assignment in order to return the assigned value and compare that to an empty string, directly in the while loop.
Here is how I'm doing it in PHP:
while((name = raw_input("Name: ")) != ''):
names.append(name)
What I'm trying to do is identical to this in functionality:
names = []
while(True):
name = raw_input("Name: ")
if (name == ''):
break
names.append(name)
Is there any way to do this in Python?
from functools import partial
for name in iter(partial(raw_input, 'Name:'), ''):
do_something_with(name)
or if you want a list:
>>> names = list(iter(partial(raw_input, 'Name: '), ''))
Name: nosklo
Name: Andreas
Name: Aaron
Name: Phil
Name:
>>> names
['nosklo', 'Andreas', 'Aaron', 'Phil']
You can wrap raw_input() to turn it into a generator:
def wrapper(s):
while True:
result = raw_input(s)
if result = '': break
yield result
names = wrapper('Name:')
which means we're back to square one but with more complex code. So if you need to wrap an existing method, you need to use nosklo's approach.
No, sorry. It's a FAQ, explained well here:
In Pydocs, and Fredrik Lundh's blog.
The reason for not allowing assignment in Python expressions is a common, hard-to-find bug in those other languages.
Many alternatives have been proposed. Most are hacks that save some typing but use arbitrary or cryptic syntax or keywords, and fail the simple criterion for language change proposals: it should intuitively suggest the proper meaning to a human reader who has not yet been introduced to the construct.
An interesting phenomenon is that most experienced Python programmers recognize the while True idiom and don’t seem to be missing the assignment in expression construct much; it’s only newcomers who express a strong desire to add this to the language.
There’s an alternative way of spelling this that seems attractive:
line = f.readline() while line:
... # do something with line...
line = f.readline()
I'm only 7 years late, but there's another solution. It's not the best solution I can think of, but it highlights an interesting use of the StopIteration exception. You can do a similar loop for chunk reading files/sockets and handle Timeouts and whatnot nicely.
names=[]
try:
while True:
f = raw_input()
if not f:
raise StopIteration
else:
names.append(f)
except StopIteration:
pass
print names
names = []
for name in iter(lambda: raw_input("Name: "), ''):
names.append(name)
PEP 572 proposes Assignment Expressions and has already been accepted. Starting with Python 3.8, you will be able to write:
while name := input("Name: "):
names.append(name)
Quoting the Syntax and semantics part of the PEP for some more examples:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
# A loop that can't be trivially rewritten using 2-arg iter()
while chunk := file.read(8192):
process(chunk)
# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]
# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]