Python Forum
Is the following code returning a generator expression? - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Is the following code returning a generator expression? (/thread-39752.html)



Is the following code returning a generator expression? - quazirfan - Apr-08-2023

I am reading Python documentation on in operator,

Source: https://docs.python.org/3/reference/expressions.html#membership-test-operations

6.10.2. Membership test operations
The operators in and not in test for membership. x in s evaluates to True if x is a member of s, and False otherwise. x not in s returns the negation of x in s. All built-in sequences and set types support this as well as dictionary, for which in tests whether the dictionary has a given key. For container types such as list, tuple, set, frozenset, dict, or collections.deque, the expression x in y is equivalent to any(x is e or x == e for e in y).

Does x is e or x == e for e in y return a generator expression which is also an iterable?


RE: Is the following code returning a generator expression? - Gribouillis - Apr-08-2023

(Apr-08-2023, 07:30 PM)quazirfan Wrote: Does x is e or x == e for e in y return a generator expression which is also an iterable?

From a syntactic point of view
(x is e or x == e for e in y)
is a "generator expression". Upon execution, this expression returns a Python object which type is "generator object". All generator objects are "iterable", which means that by applying the iter() function to these objects, it returns an "iterator".
>>> from collections.abc import Iterable, Iterator
>>> g = (x is e or x == e for e in y)
>>> g
<generator object <genexpr> at 0x7f10b26bac70>
>>> isinstance(g, Iterable)
True
>>> isinstance(iter(g), Iterator)
True
Note that "Iterable" and "Iterator" are interfaces (or abstract classes) rather than actual types.


RE: Is the following code returning a generator expression? - quazirfan - Apr-08-2023

(Apr-08-2023, 09:51 PM)Gribouillis Wrote: From a syntactic point of view
(x is e or x == e for e in y)
is a "generator expression".

Are the parenthesis part of the generator expression?


RE: Is the following code returning a generator expression? - Gribouillis - Apr-09-2023

(Apr-08-2023, 11:57 PM)quazirfan Wrote: Are the parenthesis part of the generator expression?
In a sense yes because there is no way to use them without parentheses. However when the generator expression is used as a single argument in a function call, the function call parentheses suffice
func(x is e or x == e for e in y)
If there is more than one argument, another pair of parentheses is necessary
func('spam', (x is e or x == e for e in y))
List comprehensions are like generator expressions but with square brackets.
[x is e or x == e for e in y]
They could also be written with a true generator expression
list(x is e or x == e for e in y)



RE: Is the following code returning a generator expression? - quazirfan - Apr-09-2023

(Apr-09-2023, 08:05 AM)Gribouillis Wrote: function call parentheses suffice

This is such a tricky thing. Am I correct to guess there is no difference in program output between func((x is e or x == e for e in y)) and func(x is e or x == e for e in y)?

I am pasting the generator expression doc for completion: https://docs.python.org/3/reference/expressions.html#generator-expressions

Quote:6.2.8. Generator expressions
A generator expression is a compact generator notation in parentheses:

generator_expression ::= "(" expression comp_for ")"
A generator expression yields a new generator object. Its syntax is the same as for comprehensions, except that it is enclosed in parentheses instead of brackets or curly braces.

Variables used in the generator expression are evaluated lazily when the __next__() method is called for the generator object (in the same fashion as normal generators). However, the iterable expression in the leftmost for clause is immediately evaluated, so that an error produced by it will be emitted at the point where the generator expression is defined, rather than at the point where the first value is retrieved. Subsequent for clauses and any filter condition in the leftmost for clause cannot be evaluated in the enclosing scope as they may depend on the values obtained from the leftmost iterable. For example: (x*y for x in range(10) for y in range(x, x+10)).

The parentheses can be omitted on calls with only one argument. See section Calls for details.



RE: Is the following code returning a generator expression? - deanhystad - Apr-10-2023

Why are you doing "if x is e or x == e"? Can you ever have the check for identity be True when the check for equality is False?


RE: Is the following code returning a generator expression? - bowlofred - Apr-10-2023

(Apr-10-2023, 02:27 AM)deanhystad Wrote: Can you ever have the check for identity be True when the check for equality is False?

Technically, yes. But I don't know of anything besides NaN which does so. (NaN is supposed to never be equal to any other number)

>>> x = float('nan')
>>> x is x
True
>>> x == x
False



RE: Is the following code returning a generator expression? - Gribouillis - Apr-10-2023

(Apr-10-2023, 02:27 AM)deanhystad Wrote: Why are you doing "if x is e or x == e"? Can you ever have the check for identity be True when the check for equality is False?
I think @quazirfan was only quoting the Python documentation at the point where it explains the behavior of the in operator in common containers. Note than in the test x is e or x == e, the == operator is only evaluated if x is not e. I think the documentation means that pointer equality is tried before anything else.

documentation for __eq__ Wrote:By default, object implements __eq__() by using is, returning NotImplemented in the case of a false comparison: True if x is y else NotImplemented. For __ne__(), by default it delegates to __eq__() and inverts the result unless it is NotImplemented. There are no other implied relationships among the comparison operators or default implementations
quazirfan Wrote:Am I correct to guess there is no difference
There is no difference at all.


RE: Is the following code returning a generator expression? - quazirfan - Apr-11-2023

@Gribouillis Thank you. Your answer cleared confusion on multiple levels.