Списки (list). Функции и методы списков

Do you know the difference between the following syntax?


(x for x in range(5))
tuple(range(5))

Let’s check it

4 Facts About the Lists

First off, a short review on the lists (arrays in other languages).

  • list is a type of data that can be represented as a collection of elements. Simple list looks like this –
  • lists take all possible types of data and combinations of data as their components:
>>> a = 12 >>> b = "this is text" >>> my_list = , (1, 2, 3), a] >>> print(my_list) , (1, 2, 3), 12]
  • lists can be indexed. You can get access to any individual element or group of elements using the following syntax:
& >>> a = ["red", "green", "blue"] >>> print(a) red
  • lists are mutable in Python. This means you can replace, add or remove elements.

What is List Comprehension?

Often seen as a part of functional programming in Python, list comprehensions allow you to create lists with a for loop with less code.

Let’s look at the following example.

You create a list using a for loop and a range() function.

& >>> my_list = >>> for x in range(10): ... my_list.append(x * 2) ... >>> print(my_list)

And this is how the implementation of the previous example is performed using a list comprehension:

>>> comp_list = >>> print(comp_list)

The above example is oversimplified to get the idea of syntax. The same result may be achieved simply using list(range(0, 19, 2)) function. However, you can use a more complex modifier in the first part of comprehension or add a condition that will filter the list. Something like this:

>>> comp_list = >>> print(comp_list)

Another available option is to use list comprehension to combine several lists and create a list of lists. At first glance, the syntax seems to be complicated. It may help to think of lists as an outer and inner sequences.

It’s time to show the power of list comprehensions when you want to create a list of lists by combining two existing lists.

>>> nums = >>> letters = ["A", "B", "C", "D", "E"] >>> nums_letters = [ for n in nums for l in letters] #the comprehensions list combines two simple lists in a complex list of lists. >>> print(nums_letters) >>> print(nums_letters) [, , , , , , , , , , , , , , , , , , , , , , , , ] >>>

Let’s try it with text or it’s correct to say string object.

>>> iter_string = "some text" >>> comp_list = >>> print(comp_list) ["s", "o", "m", "e", "t", "e", "x", "t"]

The comprehensions are not limited to lists. You can create dicts and sets comprehensions as well.

>>> dict_comp = {x:chr(65+x) for x in range(1, 11)} >>> type(dict_comp) >>> print(dict_comp) {1: "B", 2: "C", 3: "D", 4: "E", 5: "F", 6: "G", 7: "H", 8: "I", 9: "J", 10: "K"} >>> set_comp = {x ** 3 for x in range(10) if x % 2 == 0} >>> type(set_comp) >>> print(set_comp) {0, 8, 64, 512, 216}

Difference Between Iterable and Iterator

It will be easier to understand the concept of generators if you get the idea of iterables and iterators.

Iterable is a “sequence” of data, you can iterate over using a loop. The easiest visible example of iterable can be a list of integers – . However, it’s possible to iterate over other types of data like strings, dicts, tuples, sets, etc.

Basically, any object that has iter () method can be used as an iterable. You can check it using hasattr() function in the interpreter.

>>> hasattr(str, "__iter__") True >>> hasattr(bool, "__iter__") False

Iterator protocol is implemented whenever you iterate over a sequence of data. For example, when you use a for loop the following is happening on a background:

  • first iter () method is called on the object to converts it to an iterator object.
  • next () method is called on the iterator object to get the next element of the sequence.
  • StopIteration exception is raised when there are no elements left to call.
>>> simple_list = >>> my_iterator = iter(simple_list) >>> print(my_iterator) >>> next(my_iterator) 1 >>> next(my_iterator) 2 >>> next(my_iterator) 3 >>> next(my_iterator) Traceback (most recent call last): File "", line 1, in StopIteration

Generator Expressions

In Python, generators provide a convenient way to implement the iterator protocol. Generator is an iterable created using a function with a yield statement.

The main feature of generator is evaluating the elements on demand. When you call a normal function with a return statement the function is terminated whenever it encounters a return statement. In a function with a yield statement the state of the function is “saved” from the last call and can be picked up the next time you call a generator function.

>>> def my_gen(): ... for x in range(5): ... yield x

Generator expression allows creating a generator on a fly without a yield keyword. However, it doesn’t share the whole power of generator created with a yield function. The syntax and concept is similar to list comprehensions:

>>> gen_exp = (x ** 2 for x in range(10) if x % 2 == 0) >>> for x in gen_exp: ... print(x) 0 4 16 36 64

In terms of syntax, the only difference is that you use parentheses instead of square brackets. However, the type of data returned by list comprehensions and generator expressions differs.

>>> list_comp = >>> gen_exp = (x ** 2 for x in range(10) if x % 2 == 0) >>> print(list_comp) >>> print(gen_exp) at 0x7f600131c410>

The main advantage of generator over a list is that it takes much less memory. We can check how much memory is taken by both types using sys.getsizeof() method.

Note: in Python 2 using range() function can’t actually reflect the advantage in term of size, as it still keeps the whole list of elements in memory. In Python 3, however, this example is viable as the range() returns a range object.

>>> from sys import getsizeof >>> my_comp = >>> my_gen = (x * 5 for x in range(1000)) >>> getsizeof(my_comp) 9024 >>> getsizeof(my_gen) 88

We can see this difference because while `list` creating Python reserves memory for the whole list and calculates it on the spot. In case of generator, we receive only ”algorithm”/ “instructions” how to calculate that Python stores. And each time we call for generator, it will only “generate” the next element of the sequence on demand according to “instructions”.

On the other hand, generator will be slower, as every time the element of sequence is calculated and yielded, function context/state has to be saved to be picked up next time for generating next value. That “saving and loading function context/state” takes time.

Final Thoughts

The very first thing that might scare or discourage a newbie programmer is the scale of educational material. The trick here is to treat each concept as an option offered by language, you’re not expected to learn all the language concepts and modules all at once. There are always different ways to solve the same task. Take it as one more tool to get the job done.

Сегодня я расскажу о таком типе данных, как списки , операциях над ними и методах, о генераторах списков и о применении списков.

Что такое списки?

Списки в Python - упорядоченные изменяемые коллекции объектов произвольных типов (почти как массив, но типы могут отличаться).

Чтобы использовать списки, их нужно создать. Создать список можно несколькими способами. Например, можно обработать любой итерируемый объект (например, ) встроенной функцией list :

>>> list ("список" ) ["с", "п", "и", "с", "о", "к"]

Список можно создать и при помощи литерала:

>>> s = # Пустой список >>> l = [ "s" , "p" , [ "isok" ], 2 ] >>> s >>> l ["s", "p", ["isok"], 2]

Как видно из примера, список может содержать любое количество любых объектов (в том числе и вложенные списки), или не содержать ничего.

И еще один способ создать список - это генераторы списков . Генератор списков - способ построить новый список, применяя выражение к каждому элементу последовательности. Генераторы списков очень похожи на цикл .

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

Возможна и более сложная конструкция генератора списков:

>>> 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"]

Но в сложных случаях лучше пользоваться обычным циклом for для генерации списков.

Функции и методы списков

Создать создали, теперь нужно со списком что-то делать. Для списков доступны основные , а также методы списков.

Таблица "методы списков"

Метод Что делает
list.append (x) Добавляет элемент в конец списка
list.extend (L) Расширяет список list, добавляя в конец все элементы списка L
list.insert (i, x) Вставляет на i-ый элемент значение x
list.remove (x) Удаляет первый элемент в списке, имеющий значение x. ValueError, если такого элемента не существует
list.pop ([i]) Удаляет i-ый элемент и возвращает его. Если индекс не указан, удаляется последний элемент
list.index (x, ]) Возвращает положение первого элемента со значением x (при этом поиск ведется от start до end)
list.count (x) Возвращает количество элементов со значением x
list.sort () Сортирует список на основе функции
list.reverse () Разворачивает список
list.copy () Поверхностная копия списка
list.clear () Очищает список

Нужно отметить, что методы списков, в отличие от , изменяют сам список, а потому результат выполнения не нужно записывать в эту переменную.

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

И, напоследок, примеры работы со списками:

>>> 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]

Изредка, для увеличения производительности, списки заменяют гораздо менее гибкими

Представим себе ситуацию - вам необходимо извлечь все элементы списка и присвоить каждый из них своей определенной переменной. Например, у нас есть список описывающий человека и содержащий следующие элементы:

Person_data = ["John", "Smith", 23, "programmer"]

User_name, user_surname, user_age, user_occupation = person_data

После этого мы сможем использовать отдельно каждую созданную переменную.

Обратите внимание, что количество создаваемых переменных должно соответствовать количеству элементов в списке, иначе вы получите ошибку.

Как пользоваться генераторами в Python.

Генераторами списков в Python называются однострочные конструкции, которые позволяют создавать новые списки.

Синтаксис генераторов списков такой:

# самый простой генератор new_list =

В итоге new_list будет содержать числа от 0 до 9. Понятно, что для того чтобы создать такой список незачем пользоваться генератором. Достаточно просто воспользоваться функцией range()

# пример посложнее word = "hello" new_list =

Теперь new_list будет выглядеть так:

["h","e","l","l","o"]

Так же в генераторы списков можно вставлять конструкцию if:

# Создаем список из чисел кратных трем new_list =

В итоге получим:

Наконец, в генераторе можно использовать несколько списков и переменных:

# создание колоды карт при помощи генератора списков # масти suits = "HDCS" # ранги ranks = "23456789TJQKA" # генерируем колоду deck =

Получим следующий результат:

Представьте, сколько времени мы сэкономили, написав всего одну строчку вместо нескольких циклов .

Как извлечь элементы из подсписков в Python.

Так же, часто возникает ситуация, когда необходимо извлечь элементы из подспиков списка.

Например имеем такой список:

Outer = [, , ]

Задача создать отдельный список содержащий все элементы подсписков данного списка. Выполнить эту задачу можно при помощи все того же генератора списков:

New_list =

Таким образом получаем список со всеми элементами:

На этом на сегодня все. Удачи в освоении Python !

Генератор списков - это уже известные нам конструкции в новой "обертке". Внешне, они построены, в простейшей своей форме, на цикле "for" и призваны решать тотже спектр задач, что и классический цикл "for". Впринципе, нет такой задачи, которую можно выполнить через генератор списков и нельзя было бы выполнить через классический цикл "for", но сама структура генератора является краткой, лаконичной и гибкой в использовании. Держите в памяти то, что базой для генератора, служит цикл "for" и все, что мы выполняем при помощи этого цикла, мы можем выполнять и в генераторе. Рассмотрим простейший синтаксис генератора списка:

>>> lst =
>>> lst

>>>

>>>

Посмотрим на код более внимательно. ВНачале был создан список чисел "1,2,3,4,5", после чего следует форма записи генератора. Запись генератора списков береться в квадратные скобки. Вначале указывается действие для переменной, куда цикл помещает элементы на каждом шаге итерации, зачем следует классическая форма записи объявления цикла "for", куда передается созданный список чисел. Генератор списка возвращает список чисел, которые были сгенерированы в процессе указанного действия внутри генератора, а именно, взять элемент на каждом шаге итерации и умножить его на 2. Врезультате чего, получаем список чисел из списка "lst", Где каждый элемент умножен на 2. При использовании классического цикла "for", эта запись выглядит следующим образом:

>>> lst =
>>> lst

>>> lst2 =
>>> for i in lst:
... lst2.append(i*2)
...
>>> lst2

>>>

Согласитесь, запись в виде генератора списка, была куда более краткой. На первый взгляд, приемущества генератора списков очевидны далеко не сразу, но давайте смоделируем несколько ситуаций, где мы можем применить генератор списка, который позволит сократить количество написанного кода, а главное, позволит сократить код не в ущерб производительности и сопровождению. Кпримеру, у нас есть файл, с которого нам необходимо достать список строк. Файл находится в кодировке "utf-8" и в процессе доставания, нам необходимо декодировать строки в юникод, параллельно убрав эскейп последовательность "\n", в конце каждой строки.

>>> text = for s in open(ur"d:\dev\price.txt")]
>>> print text

>>>

Полюбуйтесь на этот код! Мы выполнили поставленную задачу в одну строку кода. Впринципе, код достаточно очевидный. Мы обратились к файлу непосредственно в цикле "for", что передало циклу объект-итератор файла. Далее цикл пробежался по строкам, и выполнил действие, которое мы указали ему вначале нашего генератора, Т.Е. Перевел каждую строку в юникод и вернул ее со срезом [:-1], что позволило удалить эскейп последовательность "\n". Собственно получившийся список, мы присвоили переменной "text", которая и содержит список обработанных строк:

>>> for i in text:
... print i
...
Прайс на чебурашек, чубурашек и чибураторов.




Чубурашка, цвет синий, характер мерзкий, цена 200 грн;
Чубурашка, цвет голубой, характер доставучий, цена 250 грн;
Чубурашка, цвет малиновый, характер клубничный, цена 300 грн;
Чибуратор, цвет хаки, характер нордический, цена 400 грн;
Чибуратор, цвет мутный, характер мутный, цена 400 грн;
Чибуратор, цвет шоколадный, характер мармеладный, цена 500 грн;
Чибуратор, цвет полосатый, характер сонный, цена 600 грн;
>>>

Это действительно удобно, причем, как я и говорил, не затрудняет чтение кода и положительно сказывается на общей производительности.

Генератор списков с условием "if"

Мы можем сделать генератор списков еще более гибким, использовав в его конструкции условие "if". Для демонстрации, решим простую задачу. Из списка чисел, нам необходимо сформировать новый список чисел, которые будут больше или равны пяти:

>>> lst =
>>> lst

>>>

>>>

Мы расширили синтаксис генератора списков условием "if", которое имеет выражение ">= 5". Генератор вернет список только тех значений, которые будут обрабатываться на шаге итерации, при котором "if" будет получать "True". Соответственно, нам вернется список чисел, которые соответствуют утверждению ">= 5".
Мы можем еще более расширить генератор списка, воспользовавшись тернарной записью "if else":

>>> 1 if 3>2 else 0
1
>>> 1 if 3 < 2 else 0
0
>>>

Напомню, что тернарная запись "if else", возвращает результат слева, если выражение после "if", возвращает "True". В противном случае, возвращается результат справа. Теперь посмотрим, как мы можем соединить это с генератором списка, решив предыдущую задачу, но поставив условие, что, как только нам встречается число в списке меньше пяти, мы возвращаем его, но прибавив к нему +5:

>>> lst

>>>

>>>

Давайте решим еще одну, менее синтетическую задачу, на основании этого синтаксиса. Возьмем нашь файлик "price.txt" и вернем в список только те строки, которые начинаются со слова "Чебурашка", а для остальных результатов, вернуть "None":

>>> text = for string in open(ur"d:\dev\price.txt")]
>>> for i in text:
... print i
...
None
Чебурашка, цвет зеленый, характер унылый, цена 100 грн;
Чебурашка, цвет красный, характер агрессивный, цена 150 грн;
Чебурашка, цвет коричневый, характер чебурашечный, цена 150 грн;
Чебурашка, цвет белый, характер настырный, цена 200 грн;
None
None
None
None
None
None
None
>>>

(Строчный метод "startswith", возвращает "True", если строка начинается с переданного в метод префикса)

Генератор словарей

Подробно останавливаться на использовании генератора, как такового, мы не будем, рассмотрим только базовый синтаксис генератора словарей. Смысл и примеры использования, остаются такими же, как и для генератора списков:

>>> lst

>>> {i:i*2 for i in lst}
{1: 2, 2: 4, 3: 6, 4: 8, 5: 10}
>>>

Все выражение генератора мы заключаем в фигурные скобочки, а в начале, в виде действия, указываем синтаксис записи пары "ключ/значение" для словаря.

Генератор множеств

Тройку встроенных генераторов Python, заканчивает генератор множеств, суть которого остается такой же, как и у предыдущих генераторов. Его базовый синтаксис выглядит следующим образом:

>>> lst =
>>> lst

>>> {i*2 for i in lst}
set()
>>>

Будте внимательны, генератор множеств, также, как и генератор словарей, заключается в фигурные скобочки, разница лишь в синтаксисе. Для генератора множеств, мы не указываем вид пары "ключ/значение", его синтаксис схож с генератором списков, но заключен в фигурные скобочки. Именно такой синтаксис, говорит Python, что это генератор множеств.

Генераторы и итераторы представляют собой инструменты, которые, как правило, используются для поточной обработки данных. В уроке рассмотрим концепцию итераторов в Python , научимся создавать свои итераторы и разберемся как работать с генераторами.

Итераторы в языке Python

Во многих современных языках программирования используют такие сущности как итераторы. Основное их назначение – это упрощение навигации по элементам объекта, который, как правило, представляет собой некоторую коллекцию (список, словарь и т.п.). Язык Python , в этом случае, не исключение и в нем тоже есть поддержка итераторов. Итератор представляет собой объект перечислитель, который для данного объекта выдает следующий элемент, либо бросает исключение, если элементов больше нет.

Основное место использования итераторов – это цикл for . Если вы перебираете элементы в некотором списке или символы в строке с помощью цикла for , то,фактически, это означает, что при каждой итерации цикла происходит обращение к итератору, содержащемуся в строке/списке, с требованием выдать следующий элемент, если элементов в объекте больше нет, то итератор генерирует исключение, обрабатываемое в рамках цикла for незаметно для пользователя.

Приведем несколько примеров, которые помогут лучше понять эту концепцию. Для начала выведем элементы произвольного списка на экран.

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

Как уже было сказано, объекты, элементы которых можно перебирать в цикле for , содержат в себе объект итератор, для того, чтобы его получить необходимо использовать функцию iter() , а для извлечения следующего элемента из итератора – функцию 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

Как видно из приведенного выше примера вызов функции next(itr) каждый раз возвращает следующий элемент из списка, а когда эти элементы заканчиваются, генерируется исключение StopIteration .

Создание собственных итераторов

Если нужно обойти элементы внутри объекта вашего собственного класса, необходимо построить свой итератор. Создадим класс, объект которого будет итератором, выдающим определенное количество единиц, которое пользователь задает при создании объекта. Такой класс будет содержать конструктор, принимающий на вход количество единиц и метод __next__() , без него экземпляры данного класса не будут итераторами.

__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))

В нашем примере при четвертом вызове функции next() будет выброшено исключение StopIteration . Если мы хотим, чтобы с данным объектом можно было работать в цикле for , то в класс SimpleIterator нужно добавить метод __iter__() , который возвращает итератор, в данном случае этот метод должен возвращать 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)

Генераторы

Генераторы позволяют значительно упростить работу по конструированию итераторов. В предыдущих примерах, для построения итератора и работы с ним, мы создавали отдельный класс. Генератор – это функция, которая будучи вызванной в функции next() возвращает следующий объект согласно алгоритму ее работы. Вместо ключевого слова return в генераторе используется yield . Проще всего работу генератор посмотреть на примере. Напишем функцию, которая генерирует необходимое нам количество единиц.

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))

Данная функция будет работать точно также, как класс SimpleIterator из предыдущего примера.

Ключевым моментом для понимания работы генераторов является то, при вызове yield функция не прекращает свою работу, а “замораживается” до очередной итерации, запускаемой функцией next() . Если вы в своем генераторе, где-то используете ключевое слово

Публикации по теме