3

I'm brand new to python 3 & my google searches have been unproductive. Is there a way to write this:

for x in range(10):
  print(x) 

as this:

print(x) for x in range(10)

I do not want to return a list as the arr = [x for x in X] list comprehension syntax does.

EDIT: I'm not actually in that specific case involving print(), I'm interested in a generic pythonic syntactical construction for

method(element) for element in list
neph
  • 151
  • 6
  • We usually use it with `list-comprehension`. – jizhihaoSAMA Jun 18 '20 at 01:40
  • `print("\n".join(map(str, range(10))))` – dawg Jun 18 '20 at 01:40
  • Thanks dawg, but I'm really looking for something that's roughly analogous to the js foreach method & really pythonic. – neph Jun 18 '20 at 01:42
  • `print("\n".join([str(x) for x in range(10)]))` – dawg Jun 18 '20 at 01:42
  • Again, thanks dawg, but I don't actually care about printing anything. I'm concerned with a generic method. But since you seem interested in helping me in my specific case, it's using the .write method on a fiona shapefile object: `newFeatureClass.write(feature) for feature in oldFeatureClass` – neph Jun 18 '20 at 01:47
  • 2
    No, there isn't just a one-line for-loop. Comprehension constructs produce the corresponding containers, lists, dicts, sets, or generator objects. `map` returns an iterator. Just use a for-loop. For-loops **are pythonic** – juanpa.arrivillaga Jun 18 '20 at 02:53
  • @juanpa.arrivillaga, containers are typically finite, an iterable may just as well represent an infinite source of data, so a generator object may not be called a container. Moreover, the OP enquires for a way that doesn't return a list comprehension, so a generator object/ iterator could be the answer to the question. – Aditya Patnaik Jun 19 '20 at 06:09
  • @AdityaPatnaik fair enough, it would more precisely stated as "produce the corresponding containers : lists, sets, and dicts; and generator objects for generator expressions" In any case, that isn't really relevant. The point is, you can *print the result of a comprehension construct*, but you should *use print inside a comprehension construct* – juanpa.arrivillaga Jun 19 '20 at 06:18
  • the OP says **I'm not actually in that specific case involving print()** , OP seeks for a way that doesn't necessarily has a print statement, its ok if it has, however the question stresses on a way to get a one liner that gives a better way to implement a loop that doesn't return a list. – Aditya Patnaik Jun 19 '20 at 06:30
  • With `print` it doesn't make sense. You materialize a container when you unpack the generator expression into the call. The OP referenced the `forEach` method, which is generally for functions with side-effects, as opposed to mappings, which should use pure-functions. The style that you should use depends on what you are trying to do and how you plan to do it. You shouldn't be will-nilly using generator expressions. So `for i in range(1_000_000_000): print(i)` takes **significantly** less memory that `print(*(i for i in range(1_000_000_000))` – juanpa.arrivillaga Jun 19 '20 at 06:38
  • i agree but why are we comparing print statements here rather than comparing generator objects with lists, if you say lists take less memory than generator objects then as per my knowledge thats a wrong understanding. Try doing the sys.getsizeof() of both for a clear comparison. – Aditya Patnaik Jun 19 '20 at 06:46
  • @AdityaPatnaik that's *not* what I'm saying. That isn't what I've stated anywhere. My **point** is that comprehension constructs, `map`, etc **are not merely generic replacements for for-statements**. They are *functional programming contructs* that should be used with *pure functions without side effects* to express mapping/filtering operations on iterables to yield some other object (usually a container, but maybe an iterator). So you shouldnt use them like you use `forEach`, for example, which generally would be used for side-effects in lieu of a for-loop. In python, you just use the loop – juanpa.arrivillaga Jun 19 '20 at 20:20
  • @juanpa.arrivillaga, so a generator expression shouldn't be used in the place of loop when the requirement is to implement `foreach`. Why? – Aditya Patnaik Jun 20 '20 at 05:38

4 Answers4

4

No, there isn't. Unless you consider this a one liner:

for x in range(6): print(x) 

but there's no reason to do that.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
1

Looks like you are looking for something like map. If the function you are calling returns None, then it won't be too expensive.

Map will return an iterator, so you are just trying to consume it. One way is:

list(map(print, range(6)))

Or using a zero length deque if you don't want the actual list elements stored.

from collections import deque

deque(map(print, range(6)), maxlen=0)
Victor Uriarte
  • 479
  • 4
  • 9
  • This is probably a similar discussion. https://stackoverflow.com/a/50938015/5208670 – Victor Uriarte Jun 18 '20 at 02:01
  • using `list(map())` is the same as using a list comprehension. It produces a list. – Boris Verkhovskiy Jun 18 '20 at 05:44
  • @boris. Fair enough. I was trying to highlight the concept of map and needed an iterator to consume it. – Victor Uriarte Jun 18 '20 at 15:24
  • it is bad style to use map for printing like this – juanpa.arrivillaga Jun 19 '20 at 06:20
  • @juanpa.arrivillaga agreed, but as the original post stated, he was using `print` as a place holder example. In his update he said he wanted an answer for a generic method. – Victor Uriarte Jun 19 '20 at 20:15
  • 1
    @VictorUriarte sure, but `map` shouldn't be used with any generic function. It should be used with pure functions without side-effects. This is fundamentally the point I've been trying to make: list comprehensions, map, etc are not merely "one-liner for loops", they exist to facilitate the expression of mapping/filtering operations on arbitrary iterables with pure functions, not a generic replacement for the `for` statement to save space – juanpa.arrivillaga Jun 19 '20 at 20:17
0

For your specific case to print a range of 6:

print(*range(6), sep='\n')

This is not a for loop however @Boris is correct.

leopardxpreload
  • 767
  • 5
  • 17
0

What you are looking for is a generator expression that returns a generator object.

print(i for i in range(10)) #<generator object <genexpr> at 0x7f3a5baacdb0>

To see the values

print(*(i for i in range(10))) # 0 1 2 3 4 5 6 7 8 9

Pros:

  • Extremely Memory Efficient.
  • Lazy Evaluation - generates next element only on demand.

Cons:

  • Can be iterated over till the stop iteration is hit, after that one cannot reiterate it.
  • Cannot be indexed like a list.

Hope this helps!

Aditya Patnaik
  • 1,490
  • 17
  • 27
  • also, a generator object may not be sliced like a list but you can use islice() from itertools library to apply slicing. To reiterate a generator object, new copies of the same could be made using tee() function from itertools which returns n copies of the object that can be iterated over,once each – Aditya Patnaik Jun 18 '20 at 14:06
  • Doesn't this still produce a list that gets passed to `print` as its `*args` – Boris Verkhovskiy Jun 18 '20 at 15:36
  • *args was passed to print just to show what the generator contains. it can be played around with like a list..like sum(generator obj) gives the same result as sum(list), where the former is a better performer in terms of memory. – Aditya Patnaik Jun 19 '20 at 05:48
  • 1
    This provides no advantage over a list comprehension, the key here is that *print isn't part of the comprehension construct*. Indeed, `print(*(i for i in whatever))` should just be `print(*whatever)` – juanpa.arrivillaga Jun 19 '20 at 06:18
  • @juanpa.arrivillaga, absolutely, however a generator object holding a 1000 numbers(88 bytes) and a list holding a 1000 numbers(9024 bytes) differ greatly in terms of how much memory they take. So there is a serious advantage, and this is one of the many advantages, a generator supports FP paradigm that eventually gives a lot of dev benefits. Try doing sys.getsizeof(i for I in range(1000)) and try doing the same with a list of 1000 numbers. – Aditya Patnaik Jun 19 '20 at 06:35