In the Python programming language, there is a special syntax construct that allows you to create filled lists according to certain rules. Such structures are called list generators. Their convenience lies in the shorter notation program code than if the list were created in the usual way.

For example, you need to create a list filled with natural numbers up to a certain number. The "classic" way would look something like this:

>>>a= >>> for i in range (1 , 15 ) : ...a.append(i) ... >>> a

It took three lines of code to create the list. The generator will do it in one:

>>> a = [ i for i in range (1 , 15 ) ] >>> a

Here construction [ i for i in range (1 , 15 ) ] is a list generator. The whole construction is enclosed in square brackets, which, as it were, says that a list will be created. Inside the square brackets, three parts can be distinguished: 1) what we do with the element (in this case, we do nothing, we just add it to the list), 2) what we take (in this case, element i), 3) where we take it from (here from the range object) . Parts are separated from each other by keywords for and in.

Consider this example:

>>> a = [ 2 , -2 , 4 , -4 , 7 , 5 ] >>> b = [i**2 for i in a] >>>b

In this case, the list generator takes each element from the list a and squares it. Thus, 1) what we do - we square the element, 2) what we take - the element, 3) where we take - from the list a .

>>> >>> b = [ i*a[ i] for i in a] >>>b

Here, the key is taken from the dictionary, and the product of the key and its value is added to the generated list.

>>> a = ( 1:10 , 2:20 , 3:30 ) >>> b = [ [ i, a[ i] ] for i in a] >>>b [, , ] >>> c = [ j for i in b for j in i] >>> c

In this example, the generated list b consists of nested lists. If the generator had omitted the square brackets in the expression [i,a[i]], then an error would occur. If you still need to get a single-level list of the keys and values ​​of the dictionary, you need to take each nested list and take each element from it. This is achieved through the nested construction for, which is shown in line c = [j for i in b for j in i]. The "classic" syntax for populating list c would look like this:

>>>c= >>> for i in b: ... for j in i: ...c.append(j) ... >>> c

At the end of the generator, you can add the construction if. For example, you need to extract all digits from a string :) if i%30 == 0 or i%31 == 0 ] >>> a

Thus, generators make it easier and faster to create lists. However, they cannot replace rather complex structures. For example, when the validation condition should include the branch else.

The Pyrhon programming language has a special syntax that allows you to create filled lists based on certain rules. The generated lists can be different, the content of the structure can be different, so they are called list generators. They are convenient because the entries are not as long as with the traditional method of creating lists.

For example, you need a list of natural numbers up to a specific number. traditional method will look like this:

>>> a = >>> for i in range(1,15): ... a.append(i) ... >>>

The list took three lines of code. And the generator needs only one:

>>> a = >>> a

A construct is a list generator. All constructions must be placed in square lists, which reflects the creation of the list. There are three parts inside the brackets:

  1. What will we do with the elements (in our situation, we do nothing, we just add it to the list).
  2. What will we take (we take element i).
  3. Where will we take it from (from the range object). To separate parts, use the keywords in and for.

Let's look at an example

>>> a = >>> b = >>> b

In this situation, we take each element of the list and square it. From here:

  1. We do - we raise our element to a square.
  2. We take an element.
  3. From - from the list a.
>>> a = (1:10, 2:20, 3:30) >>> b = for i in a] >>> b

Here we take the key in the dictionary, and the product of the key and its value gets into the generated list.

>>> a = (1:10, 2:20, 3:30) >>> b = [] for i in a] >>> b [, , ] >>> c = >>> c

In this case, list b contains nested lists. Omitting square brackets in the generator in the expression ] would result in an error. If you need a single-level list with keys from dictionary values, you need to take each nested list and take each component from there. This is done with a nested for construct. The traditional listing syntax is:

>>> c = >>> for i in b: ... for j in i: ... c.append(j) ... >>> c

List comprehensions can be supplemented with an if construct. For example, you need to extract all numbers from a string:

>>> a="lsj94ksd231 9" >>> b=

Or fill the list with numbers that are multiples of 31 or 30:

>>> a = >>> a

Lists are much easier and faster to create. But, they are not suitable for replacing rather complex structures. For example, if there is an else branch in the check condition.

Run out of money, and payday is still a couple of weeks away? You can borrow, but what if there is no one? Don't go to the bank for a loan. In this case, microloans will help you. Just go to the site, fill out an application (it's very simple and fast) and in a few minutes you will receive money! Very convenient and fast, and most importantly, no need to ask anyone!

List comprehensions (list generators), oddly enough, are designed for convenient processing of lists, which include both the creation of new lists and the modification of existing ones.

Let's say we need to get a list of odd numbers not exceeding 25. In principle, just getting acquainted with the work of the xrange command, it is not difficult to solve this problem.

Res = for x in xrange(1, 25, 2): res.append(x) ... print res

In general, the result obtained completely suits us with everything, except for a long record. This is where our "sugar" will come to the rescue. In the very simple form, he usually

Res = ... print res

The syntax is basically simple. The entire expression is written in square brackets. First comes an expression that will set the elements of the list, then - a loop with which you can change the expression. Both parts can be arbitrarily complex. For example, here's how you can get a list of the squares of the same odd numbers.

Optionally, you can add additional terms filtration. For example, let's modify our previous example so that the squares of numbers divisible by 3 are excluded.

Res = ... print res

Task 6.1. List generator

Need to get a list binary numbers which are not squares.

Generators

Constructs like mylist = form lists of elements whose values ​​are stored in memory. You can apply the for i in mylist: print(i) construct to them to work with the elements as many times as you like.

Generators are also iterable objects, but they can only be read once. This is because they do not store values ​​in memory, but generate them on the fly:

mygenerator = (x*x for x in range(3)) for i in mygenerator: print(i)

Everything is the same, except that parentheses are used instead of square ones. BUT: you cannot apply the for i in mygenerator construct a second time, since the generator can only be used once: it evaluates to 0, then forgets about it and evaluates to 1, finishing with 4 - one after the other. You also can't get the number of elements with len() . Generators cannot be sliced ​​by mygenerator . But, generators allow you to reduce the amount of memory to run the program.

Yield

Yield is a keyword that is used similar to return - the difference is that the function will return a generator.

Def createGenerator() : mylist = range(3) for i in mylist: yield i*i mygenerator = createGenerator() # create a generator for i in mygenerator: print(i)

Task 6.2. Tetrahedral Number Generator

Using the triangular number generator, create a tetrahedral number generator.

Task 6.3. transfusion generator

There is a school problem about obtaining the required volume using an infinite pool and two buckets. For example: you need to get 4 liters using two buckets with a capacity of 3 and 5 liters. There is a solution to it by the billiard ball method.

It is necessary to create a generator that produces pairs of numbers - the fullness of the vessels. Work example:

Buckets = pool(3,5) for a,b in buckets: print("a=",a," b=",b) if b==4: break

Today I will talk about such a data type as lists, their operations and methods, list comprehensions, and the use of lists.

What are lists?

Lists in Python are ordered mutable collections of objects of arbitrary types (much like an array, but the types may differ).

To use lists, you need to create them. There are several ways to create a list. For example, you can process any iterable object (for example, ) with the built-in function list:

>>> list("list") ["list"]

A list can also be created using a literal:

>>> s = # Empty list >>> l = [ "s" , "p" , [ "isok" ], 2 ] >>> s >>> l ["s", "p", ["isok "], 2]

As you can see from the example, a list can contain any number of any objects (including nested lists), or it can contain nothing.

And another way to create a list is list generators. A list comprehension is a way to construct a new list by applying an expression to each element of a sequence. List comprehensions are very similar to a loop.

>>> c = [ c * 3 for c in "list" ] >>> c ["lll", "iii", "sss", "ttt"]

A more complex construction of the list generator is also possible:

>>> c = [ c * 3 for c in "list" if c != "i" ] >>> c ["lll", "sss", "ttt"] >>> c = [ c + d for c in "list" if c != "i" for d in "spam" if d != "a" ] >>> c ["ls", "lp", "lm", "ss", "sp", "sm", "ts", "tp", "tm"]

But in complex cases, it is better to use a regular for loop to generate lists.

List Functions and Methods

Create created, now you need to do something with the list. Basic and list methods are available for lists.

List methods table

MethodWhat is he doing
list.append(x)Adds an element to the end of the list
list.extend(L)Extends the list list by appending all elements of the list L to the end.
list.insert(i, x)Inserts the value x on the i-th element
list.remove(x)Removes the first element in the list that has the value x. ValueError if no such element exists
list.pop([i])Removes the i-th element and returns it. If no index is specified, the last element is removed.
list.index(x,])Returns the position of the first element with value x (searching from start to end)
list.count(x)Returns the number of elements with value x
list.sort() Sorts a list based on a feature
list.reverse() Expands the list
list.copy() Shallow copy of the list
list.clear() Clears the list

It should be noted that list methods, unlike , change the list itself, and therefore the result of the execution does not need to be written to this variable.

>>> l = [ 1 , 2 , 3 , 5 , 7 ] >>> l . sort() >>> l >>> l = l . sort() >>> print(l) None

And finally, examples of working with lists:

>>> a = [ 66.25 , 333 , 333 , 1 , 1234.5 ] >>> print (a . count (333 ), a . count (66.25 ), a . count ("x")) 2 1 0 >>> a. insert (2 , - 1 ) >>> a . append(333) >>> a >>> a . index (333 ) 1 >>> a . remove(333) >>> a >>> a . reverse() >>> a >>> a . sort() >>> a [-1, 1, 66.25, 333, 333, 1234.5]

Occasionally, to increase performance, lists are replaced with much less flexible ones.

Generators and iterators are tools typically used for streaming data. In the lesson, we will look at the concept of iterators in Python, learn how to create your own iterators and figure out how to work with generators.

Iterators in Python

In many modern languages programming uses such entities as iterators. Their main purpose is to simplify navigation through the elements of an object, which, as a rule, is a collection (list, dictionary, etc.). Language Python, in this case, is no exception, and it also has support for iterators. An iterator is an enumerator object that, for a given object, returns next element, or throws an exception if there are no more elements.

The main place to use iterators is in a loop. for. If you are iterating over the elements in some list or the characters in a string with a loop for, then, in fact, this means that with each iteration of the loop, the iterator contained in the string / list is accessed, with the requirement to return the next element, if there are no more elements in the object, then the iterator throws an exception processed within the loop for invisible to the user.

Here are some examples to help you better understand this concept.First, let's display the elements of an arbitrary list on the screen.

> > > num_list => > > for i in num_list: print (i) 1 2 3 4 5

As already mentioned, objects whose elements can be iterated in a loop for, contain an iterator object, in order to get it you need to use the function iter(), and to extract the next element from the iterator - the function next().

> > > itr = iter (num_list) > > > print (next(itr)) 1 > > > print (next(itr)) 2 > > > print (next(itr)) 3 > > > print (next(itr )) 4 > > > print (next(itr)) 5 > > > print (next(itr)) Traceback (most recent call last): File " " , line 1 , in< module>print (next(itr)) StopIteration

As you can see from the example above, the function call next(itr) returns the next element from the list each time, and when those elements run out, an exception is thrown StopIteration.

Creating Your Own Iterators

If you need to iterate over elements within an object of your own class, you need to build your own iterator. Let's createa class whose object will be an iterator producing a certain number of units, which the user specifies when creating the object. Such a class will contain a constructor that takes the number of units as input and a method __next__(), without it, instances of this class will not be iterators.

__init__ < self .limit: self .counter += 1 return 1 else : raise StopIteration s_iter1 = SimpleIterator(3 ) print (next(s_iter1)) print (next(s_iter1)) print (next(s_iter1)) print (next(s_iter1))

In our example, on the fourth function call next() an exception will be thrown StopIteration. If we want to be able to work with a given object in a loop for, then to the class SimpleIterator need to add method __iter__(), which returns an iterator, in this case, this method should return self.

class SimpleIterator : def __iter__(self ): return self def __init__(self , limit ): self .limit = limit self .counter = 0 def __next__ (self ): if self .counter< self .limit: self .counter += 1 return 1 else : raise StopIteration s_iter2 = SimpleIterator(5 ) for i in s_iter2: print (i)

Generators

Generators make iterator construction much easier. In the previous examples, to build and work with an iterator, we created a separate class. A generator is a function that, when called in a function next() returns the next object according to the algorithm of its work. Instead of keyword return used in the generator yield. The easiest way to see how a generator works is with an example. Let's write a function that generates the number of units we need.

def simple_generator (val ): while val > 0 : val -= 1 yield 1 gen_iter = simple_generator(5 ) print (next(gen_iter)) print (next(gen_iter)) print (next(gen_iter)) print (next(gen_iter) ) print (next(gen_iter)) print (next(gen_iter))

This function will work exactly like the class SimpleIterator from the previous example.

The key to understanding how generators work is that when you call yield the function does not stop its work, but is “frozen” until the next iteration launched by the function next(). If you are in your generator, use the keyword somewhere