Python list comprehension syntax showing output expression as "optional"? - python

This following page [see below] has a syntax description for a Python list comprehension which says that the output expression is "Optional." I haven't seen this "optional" designation elsewhere and it doesn't seem that a list comprehension would work without it. EG.
>>> llist = [1, 2, 3]
# list comprehension with output expression works
>>> listc = [num for num in llist]
# list comprehension without output expression fails
>>> listc2 =[for num in llist]
File "<stdin>", line 1
listc2 =[for num in llist]
^
SyntaxError: invalid syntax
** Here is the page:**
https://python-reference.readthedocs.io/en/latest/docs/comprehensions/list_comprehension.html
and here is the description from that page:
[expression(variable) for variable in input_set [predicate][, …]]
expression
Optional. An output expression producing members of the new set from members of the input set that satisfy the predicate expression.
variable
Required. Variable representing members of an input set.
input_set
Required. Represents the input set.
predicate
Optional. Expression acting as a filter on members of the input set.
[, …]]
Optional. Another nested comprehension.
Possibly they are trying to say that you can start a list comprehension with a bare variable, but that is still an expression, correct?

Looks like the doc is a bit unclear. You do need something on the left hand side. Otherwise the comprehension doesn't make much sense.

The page you have linked in an unofficial reference for Python, and as you can see on the GitHub page, it hasn't been updated in about 4 years. If you would like the up to date, and more importantly, correct information, go to the official documentation
Here is the link relevent to list comprehensions and their syntax
https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions
A list comprehension consists of brackets containing an expression
followed by a for clause, then zero or more for or if clauses.

The page you mentioned is quite clear about the expression. It's true, that in [expression(variable) for variable in input_set [predicate][, …]] the expression is optional, you may leave the variable as is, and it will still work. Moreover, you may leave there anything you like, not even remotely connected to the variable, like a number 42, and it still works.
Probably the original intention of the authors of the original page was to explain that you don't have to do anything with the loop variable if you don't want to an leave it as is.

Related

Why I can't use pass in python if else statement when use condition in a single line [duplicate]

This question already has answers here:
Skip elements on a condition based in a list comprehension in python
(3 answers)
Closed last month.
I want to check if an item is in a list and if not, I want to append it to the list.
Usually I would write it:
if item not in list:
list.append(item)
else:
pass
However, I got to the point where I try to keep my code shorter and got to this:
list.append(item) if item not in list else list
To be fair, only list.append(item) if item not in list is my own creation. The else statement is due to insistence of PyCharm.
Now to my question: Why can't I follow up the else statement with pass but must write list instead. I can't wrap my head around it, nor did Google help too.
Thanks for your clarifications.
There is a difference between an if statement and a conditional expression.
When you write
if condition:
this()
else:
that()
you are writing a statement. It is an imperative construct — it does something. And the else bit is optional; if it is omitted, the statement will do nothing if the condition is not fulfilled.
The this if condition else that construct is an expression. It computes a value. It always has to compute a value, so the else bit has to be there. Using it for its side effects, for example by calling `list.append(), which doesn't return anything useful, is... not exactly wrong, but... well, it is wrong. Not technically, but philosophically.
So, when you want to compute a value, in one of two possible ways, and the whole thing fits in a line or so, use a conditional expression. If you want to do either of two things, one of which may be nothing, use an if statement.
Notice that you write
if temperature < 0:
coat = thick
else:
coat = thin
but
coat = thick if temperature < 0 else thin
In the first case, you have an if statement that selects which of two assignment statements to execute. In the second case, you have a single assignment statement, which uses a conditional expression to decide which value to assign.
Expressions can be used as statements (in which case their value is simply ignored), but statements have no value, and thus cannot be used as expressions.
In your first snippet, the else statement is redundant, i.e.
if item not in a_list:
list.append(item)
is enough and is as short and idiomatic as it can get (you might want to try sets for performance though).
In the second snippet, you're using a conditional expression to append to a list, which is not what those expressions are for. A conditional expression must have a value regardless of the condition, and pass is not a value. Use the conditional statements like above unless you need to compute a value based on the condition.
From docs(also provided by Pycharm):
pass is a null operation — when it is executed, nothing happens. It is useful as a placeholder when a statement is required syntactically, but no code needs to be executed, for example:
def f(arg): pass # a function that does nothing (yet)
In python it's not allowed if you are using ternary operator interpretation, so in else you need to do something
so your solution is:
if item not in list:
list.append(item)
Or use set()
set.add(item)
You can shorten your code even more by using the and operator
item not in list and list.append(item)
It will only execute list.append(item) if item not in list returns True

Converting code to a list comprehension

I wrote a bit of code to iterate over a list to see if a line contained one or more keywords:
STRINGS_TO_MATCH = [ "Foo",
"Bar",
"Oggle" ]
for string in STRINGS_TO_MATCH
if string in line:
val_from_line = line.split(' ')[-1]
Does anyone happen to know if there is a way to make this more readable? Would a list comprehension be a better fit here?
The thing to remember here is that comprehensions are expressions, whose purpose is to create a value - list comprehensions create lists, dict comprehensions create dicts, and set comprehensions create sets. They are unlikely to help in this case, because you aren't creating any such object.
Your code sample is incomplete, because it doesn't do anything with the val_from_line values that it extracts. I am presuming that you want to extract the last "word" from a line which contains any of the strings in STRINGS_TO_MATCH, but it's difficult to work with such incomplete information so this answer might, for all I know, be totally useless.
Assuming I'm correct, the easiest way to find out if line contains any of the STRINGS_TO_MATCH is to use the expression
any(s in line for s in STRINGS_TO_MATCH)
This uses a so-called generator expression, which is similar to a list comprehension - the interpreter can iterate over it to produce a sequence of values - but it doesn't go as far as creating a list of the values, it just creates them as the client code (in this case the any built-in function) requests them. So I might rewrite your code as
if any(s in line for s in STRINGS_TO_MATCH):
val_from_line = line.split(' ')[-1]
I'll leave you to decide what you actually want to do after that, with the warning note that after this code executes val_from_line may or may not exist (depending on whether or not the condition was true), which is never an entirely comfortable situation.

Python: how to ensure method gets a list

I have a method that takes a list of strings. Unfortunately, if the list is only one item long, Python treats this list as a string.
This post has a method for checking whether something is a string, and converting it to a list if it is:
Python: How to define a function that gets a list of strings OR a string
But this seems an incredibly redundant way of getting the item that I passed in as a list to in fact be a list. Is there a better way?
You are probably using tuples, not lists, and forgetting to add the comma to the one-item tuple literal(s). ('foo') is interpreted as simply 'foo' which would match what you are saying. However, adding a comma to one-item tuple literals will solve this. ('foo',) returns, well, ('foo',).
I'm not sure I believe you, python shouldn't behave that way, and it doesn't appear to:
>>> def foo(lst):
print type(lst)
>>> foo(['bar'])
<type 'list'>
That post was about a different thing, they wanted the ability to pass a single string or a list of strings and handle both cases as if they were lists of strings. If you're only passing in a list, always treating it as a list should be fine.
Python shouldn't do that with a list. A singleton tuple, though, has syntax different from singleton lists:
(1) == 1 # (1) is 1
[1] != 1 # [1] is a singleton list
(1,) != 1 # (1,) is a singleton tuple
You are mistaken. Python does no such transformation to lists of a single element.
Double, Triple check that you are putting the [] around the the item you are passing.
If you still can't get it working show us the code!

For...in questions (Python)

I was trying some different ways to run some for...in loops. Consider a list of lists:
list_of_lists = []
list = [1, 2, 3, 4, 5]
for i in range(len(list)):
list_of_lists.append(list) # each entry in l_o_l will now be list
Now let's say I want to have the first "column" of l_o_l be included in a separate list, a.
There are several ways I can go about this. For example:
a = [list[0] for list in list_of_lists] # this works (a = [1, 1, 1, 1, 1])
OR
a=[]
for list in list_of_lists:
a.append(hit[0]) #this also works
For the second example, however, I would imagine the "full" expansion to be equivalent to
a=[]
a.append(list[0] for list in list_of_lists) #but this, obviously, produces a generator error
The working "translation" is, in fact,
a=[]
a.append([list[0] for list in list_of_lists]) #this works
My question is on interpretation and punctuation, then. How come Python "knows" to append/does append the list brackets around the "list[0] for list in list_of_lists" expansion (and thus requires it in any rewrite)?
The issue here is that list comprehensions and generator expressions are not just loops, they are more than that.
List comprehensions are designed to be an easy way to build up a list from an iterable, as you have shown.
Your latter two examples both don't work - in both cases you are appending the wrong thing to the list - in the first case, a generator, the second appends a list inside your existing list. Neither of these are what you want.
You are trying to do something in two different ways at the same time, and it doesn't work. Just use the list comprehension - it does what you want to do in the most efficient and readable way.
Your main problem is you seem to have taken list comprehensions and generator expressions and not understood what they are and what they are trying to do. I suggest you try to understand them further before using them.
My question is on interpretation and punctuation, then. How come
Python "knows" to append/does append the list brackets around the
"hit[0] for list in list_of_lists" expansion (and thus requires it in
any rewrite)?
Not sure what that is supposed to mean. I think you might be unaware that in addition to list comprehensions [i*2 for i in range(0,3)] there are also generator expressions (i*2 for i in range(0,3)).
Generator expressions are a syntax for creating generators that perform a mapping, just like a list comprehension (but as a generator). Any list comprehension [c] can be rewritten list(c). The reason why there is a naked c inside list() is because where generator expressions appear as a parameter to a call, it is permitted to drop the brackets. This is what you are seeing in a.append(hit[0] for list in list_of_lists).

Python 3.x dictionary-based keygen help?

I'm studing Python for one month and I'm trying to make a keygen application by using the dictionary. The idea was to compare each letter in name = input('Name: ') to dict.keys() and print as result dict.values() for each letter of name equal to dict.keys(). That's what I wrote:
name = input('Name: ')
kalg = dict()
kalg['a'] = '50075'
kalg['b'] = '18099'
kalg['c'] = '89885'
etc...
I tryed writing this...
for x in kalg.keys():
print(x)[/code]
...but i need to keep print(x) result but i don't know how to do it! If i do this:
for x in kalg.keys():
a = x
'a' keeps only the last key of the dictionary :(. I thought it was because print(x) prints each key of dict.keys() on a new line but i don't know how to solve it (I tryed by converting type etc... but it didn't work).
Please can you help me solve this? I also don't know how to compare each letter of a string with another string and print dict.values() as result and in the right position.
Sorry for this stupid question but i'm too excited in writing python apps :)
# Karl
I'm studing Python over two differt books: 'Learning Python' by Mark Luts which covers Python
2 and a pocket which covers Python 3. I examined the list comprehension ón the pocket one and Imanaged to write three other variants of this keygen. Now i want to ask you how can I implementthe source code of this keygen in a real application with a GUI which verify if name_textbox andkey_textbox captions match (i come from basic so that was what i used to write, just to give youan idea) as the keygen output result. I know i can try to do this by my own (I did but with nosuccess) but I would like to first complete the book (the pocket one) and understand all the mainaspects of Python. Thank you for the patience.
Calling print can't "keep" anything (since there is no variable to store it in), and repeatedly assigning to a variable replaces the previous assignments. (I don't understand your reasoning about the problem; how print(x) behaves has nothing to do with how a = x behaves, as they're completely different things to be doing.)
Your question boils down to "how do I keep a bunch of results from several similar operations?" and on a conceptual level, the answer is "put them into a container". But explicitly putting things into the container is more tedious than is really necessary. You have an English description of the data you want: "dict.values() for each letter of name equal to dict.keys()". And in fact the equivalent Python is shockingly similar.
Of course, we don't actually want a separate copy of dict.values() for each matching letter; and we don't actually want to compare the letter to the entire set of dict.keys(). As programmers, we must be more precise: we are checking whether the letter is a key of the dict, i.e. if it is in the set of dict.keys(). Fortunately, that test is trivial to write: for a given letter, we check letter in dict. When the letter is found, we want the corresponding value; we get that by looking it up normally, thus dict[letter].
Then we wrap that all up with our special syntax that gives us what we want: the list comprehension. We put the brackets for a list, and then inside we write (some expression that calculates a result from the input element) for (a variable name for the input elements, so we can use it in that first expression) in (the source of input elements); and we can additionally filter the input elements at the same time, by adding if (some condition upon the input element).
So that's simple enough: [kalg[letter] for letter in name if letter in kalg]. Notice that I have name as the "source of elements", because that's what it should be. You explained that perfectly clearly in your description of the problem - why are you iterating over dict.keys() in your existing for-loops? :)
Now, this expression will give us a list of the results, so e.g. ['foo', 'bar', 'baz']. If we want one continuous string (I assume all the values in your dict are strings), then we'll need to join them up. Fortunately, that's easy as well. In fact, since we're going to pass the results to a function taking one argument, there is a special syntax rule that will let us drop the square brackets, making things look quite a bit neater.
It's also easier than you're making it to initialize the dict in the first place; idiomatic Python code rarely actually needs the word dict.
Putting it all together:
kalg = {'a': '50075', 'b': '18099', 'c': '89885'} # etc.
name = input('Name: ')
print(''.join(kalg[letter] for letter in name if name in kalg))
I can only guess, but this could be what you want:
name = input('Name: ')
kalg = {'a':'50075', 'b': '18099', 'c': '89885'}
keylist = [kalg[letter] for letter in name]
print(" ".join(keylist))

Categories