Введение
Последовательности Python - это упорядоченные коллекции элементов. Они индексируются целыми числами.
This tutorial is from open-source community. Access the source code
Последовательности Python - это упорядоченные коллекции элементов. Они индексируются целыми числами.
В Python есть три последовательных типа данных.
'Hello'. Строка - это последовательность символов.[1, 4, 5].('GOOG', 100, 490.1).Все последовательности упорядочены, индексируются целыми числами и имеют длину.
a = 'Hello' ## Строка
b = [1, 4, 5] ## Список
c = ('GOOG', 100, 490.1) ## Кортеж
## Индексированный порядок
a[0] ## 'H'
b[-1] ## 5
c[1] ## 100
## Длина последовательности
len(a) ## 5
len(b) ## 3
len(c) ## 3
Последовательности можно копировать: s * n.
>>> a = 'Hello'
>>> a * 3
'HelloHelloHello'
>>> b = [1, 2, 3]
>>> b * 2
[1, 2, 3, 1, 2, 3]
>>>
Последовательности одного и того же типа можно конкатенировать: s + t.
>>> a = (1, 2, 3)
>>> b = (4, 5)
>>> a + b
(1, 2, 3, 4, 5)
>>>
>>> c = [1, 5]
>>> a + c
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "list") to tuple
Слайсинг означает получение подпоследовательности из последовательности. Синтаксис: s[start:end]. Где start и end - это индексы подпоследовательности, которую вы хотите получить.
a = [0,1,2,3,4,5,6,7,8]
a[2:5] ## [2,3,4]
a[-5:] ## [4,5,6,7,8]
a[:3] ## [0,1,2]
start и end должны быть целыми числами.В списках срезы можно перезаписывать и удалять.
## Перезапись
a = [0,1,2,3,4,5,6,7,8]
a[2:4] = [10,11,12] ## [0,1,10,11,12,4,5,6,7,8]
Примечание: Перезаписанный срез не обязательно должен иметь ту же длину.
## Удаление
a = [0,1,2,3,4,5,6,7,8]
del a[2:4] ## [0,1,4,5,6,7,8]
Существует несколько общих функций для сокращения последовательности до одного значения.
>>> s = [1, 2, 3, 4]
>>> sum(s)
10
>>> min(s)
1
>>> max(s)
4
>>> t = ['Hello', 'World']
>>> max(t)
'World'
>>>
Цикл for итерируется по элементам последовательности.
>>> s = [1, 4, 9, 16]
>>> for i in s:
... print(i)
...
1
4
9
16
>>>
На каждой итерации цикла вы получаете новый элемент для работы. Это новое значение помещается в переменную итерации. В этом примере переменной итерации является x:
for x in s: ## `x` - это переменная итерации
...statements
На каждой итерации предыдущее значение переменной итерации перезаписывается (если оно было). После завершения цикла переменная сохраняет последнее значение.
Вы можете использовать оператор break, чтобы досрочно выйти из цикла.
for name in namelist:
if name == 'Jake':
break
...
...
statements
Когда выполняется оператор break, цикл завершается, и выполнение продолжается с следующих statements. Оператор break действует только на самый вложенный цикл. Если этот цикл находится внутри другого цикла, он не остановит внешний цикл.
Для пропуска одного элемента и перехода к следующему используйте оператор continue.
for line in lines:
if line == '\n': ## Пропустить пустые строки
continue
## Дальнейшие инструкции
...
Это полезно, когда текущий элемент не представляет интерес или должен быть проигнорирован при обработке.
Если вам нужно подсчитывать, используйте range().
for i in range(100):
## i = 0,1,...,99
Синтаксис: range([start,] end [,step])
for i in range(100):
## i = 0,1,...,99
for j in range(10,20):
## j = 10,11,..., 19
for k in range(10,50,2):
## k = 10,12,...,48
## Обратите внимание, как оно считает с шагом 2, а не 1.
start является необязательным. По умолчанию 0.step является необязательным. По умолчанию 1.range() вычисляет значения по мере необходимости. Он не фактически хранит большой диапазон чисел.Функция enumerate добавляет дополнительное значение счетчика к итерации.
names = ['Elwood', 'Jake', 'Curtis']
for i, name in enumerate(names):
## Цикл с i = 0, name = 'Elwood'
## i = 1, name = 'Jake'
## i = 2, name = 'Curtis'
Общая форма: enumerate(sequence [, start = 0]). start является необязательным. Хороший пример использования enumerate() - отслеживание номеров строк при чтении файла:
with open(filename) as f:
for lineno, line in enumerate(f, start=1):
...
В конце концов, enumerate - это просто удобный шорткат для:
i = 0
for x in s:
statements
i += 1
Использование enumerate требует меньше набираемых символов и работает немного быстрее.
Вы можете выполнять итерацию с несколькими переменными итерации.
points = [
(1, 4),(10, 40),(23, 14),(5, 6),(7, 8)
]
for x, y in points:
## Цикл с x = 1, y = 4
## x = 10, y = 40
## x = 23, y = 14
## ...
При использовании нескольких переменных каждый кортеж распаковывается в набор переменных итерации. Количество переменных должно соответствовать количеству элементов в каждом кортеже.
Функция zip принимает несколько последовательностей и создает итератор, который объединяет их.
columns = ['name','shares', 'price']
values = ['GOOG', 100, 490.1 ]
pairs = zip(columns, values)
## ('name', 'GOOG'), ('shares',100), ('price',490.1)
Для получения результата необходимо выполнить итерацию. Можно использовать несколько переменных для распаковки кортежей, как показано ранее.
for column, value in pairs:
...
Одним из распространенных применений zip является создание пар ключ/значение для построения словарей.
d = dict(zip(columns, values))
Попробуйте некоторые базовые примеры подсчета:
>>> for n in range(10): ## Считаем 0... 9
print(n, end=' ')
0 1 2 3 4 5 6 7 8 9
>>> for n in range(10,0,-1): ## Считаем 10... 1
print(n, end=' ')
10 9 8 7 6 5 4 3 2 1
>>> for n in range(0,10,2): ## Считаем 0, 2,... 8
print(n, end=' ')
0 2 4 6 8
>>>
Взаимодейтивно экспериментируйте с некоторыми операциями по сокращению последовательностей.
>>> data = [4, 9, 1, 25, 16, 100, 49]
>>> min(data)
1
>>> max(data)
100
>>> sum(data)
204
>>>
Попробуйте выполнить цикл по данным.
>>> for x in data:
print(x)
4
9
...
>>> for n, x in enumerate(data):
print(n, x)
0 4
1 9
2 1
...
>>>
Иногда конструкция for, len() и range() используются новичками в каком-то ужасном фрагменте кода, который выглядит, словно вывалился из глубин старого生锈的 C-программа.
>>> for n in range(len(data)):
print(data[n])
4
9
1
...
>>>
Не делайте так! Не только чтение этого кода вызывает отвращение у всех, он неэффективен по памяти и работает значительно медленнее. Просто используйте обычный цикл for, если хотите выполнить итерацию по данным. Используйте enumerate(), если по какой-то причине вам нужен индекс.
Помните, что файл missing.csv содержит данные о портфеле акций, но некоторые строки имеют пропущенные данные. С использованием enumerate() модифицируйте программу pcost.py так, чтобы она выводила номер строки вместе с предупреждением, когда встречает плохие данные.
>>> cost = portfolio_cost('/home/labex/project/missing.csv')
Строка 4: Не удалось преобразовать: ['MSFT', '', '51.23']
Строка 7: Не удалось преобразовать: ['IBM', '', '70.44']
>>>
Для этого вам нужно изменить несколько частей кода.
...
for rowno, row in enumerate(rows, start=1):
try:
...
except ValueError:
print(f'Строка {rowno}: Плохая строка: {row}')
В файле portfolio.csv первая строка содержит заголовки столбцов. Везде в предыдущем коде мы просто игнорировали их.
>>> f = open('/home/labex/project/portfolio.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name','shares', 'price']
>>>
Однако, что если бы вы могли использовать заголовки для чего-то полезного? Именно здесь функция zip() приходит на помощь. Сначала попробуйте это, чтобы сопоставить заголовки файла с одной строкой данных:
>>> row = next(rows)
>>> row
['AA', '100', '32.20']
>>> list(zip(headers, row))
[ ('name', 'AA'), ('shares', '100'), ('price', '32.20') ]
>>>
Заметьте, как zip() сопоставляет заголовки столбцов с значениями столбцов. Здесь мы использовали list(), чтобы превратить результат в список, чтобы вы могли его увидеть. Обычно zip() создает итератор, который должен быть использован в цикле for.
Это сопоставление является промежуточным этапом для создания словаря. Теперь попробуйте это:
>>> record = dict(zip(headers, row))
>>> record
{'price': '32.20', 'name': 'AA','shares': '100'}
>>>
Это преобразование является одним из самых полезных приемов, которые стоит знать при обработке большого количества файлов с данными. Например, предположим, что вы хотели, чтобы программа pcost.py работала с различными входными файлами, не зависимо от того, в каком столбце фактически находятся имя, количество акций и цена.
Модифицируйте функцию portfolio_cost() в pcost.py так, чтобы она выглядела так:
## pcost.py
def portfolio_cost(filename):
...
for rowno, row in enumerate(rows, start=1):
record = dict(zip(headers, row))
try:
nshares = int(record['shares'])
price = float(record['price'])
total_cost += nshares * price
## Это ловит ошибки в преобразованиях int() и float() выше
except ValueError:
print(f'Строка {rowno}: Плохая строка: {row}')
...
Теперь, попробуйте вашу функцию на совершенно другом файле с данными portfoliodate.csv, который выглядит так:
name,date,time,shares,price
"AA","6/11/2007","9:50am",100,32.20
"IBM","5/13/2007","4:20pm",50,91.10
"CAT","9/23/2006","1:30pm",150,83.44
"MSFT","5/17/2007","10:30am",200,51.23
"GE","2/1/2006","10:45am",95,40.37
"MSFT","10/31/2006","12:05pm",50,65.10
"IBM","7/9/2006","3:15pm",100,70.44
>>> portfolio_cost('/home/labex/project/portfoliodate.csv')
44671.15
>>>
Если вы сделали это правильно, вы обнаружите, что ваша программа по-прежнему работает, даже если файл с данными имеет совершенно другой формат столбцов, чем раньше. Это круто!
Изменение, сделанное здесь, незаметно, но существенно. Вместо того, чтобы portfolio_cost() был жестко закодирован для чтения одного фиксированного формата файла, новая версия читает любой CSV-файл и выбирает из него интересующие значения. Пока файл имеет нужные столбцы, код будет работать.
Модифицируйте программу report.py, которую вы написали в разделе 2.3, так, чтобы она использовала ту же технику для выбора заголовков столбцов.
Попробуйте запустить программу report.py на файле portfoliodate.csv и убедитесь, что она дает ту же ответ, что и раньше.
Словарь сопоставляет ключи значениям. Например, словарь цен на акции.
>>> prices = {
'GOOG' : 490.1,
'AA' : 23.45,
'IBM' : 91.1,
'MSFT' : 34.23
}
>>>
Если использовать метод items(), можно получить пары (ключ, значение):
>>> prices.items()
dict_items([('GOOG', 490.1), ('AA', 23.45), ('IBM', 91.1), ('MSFT', 34.23)])
>>>
Однако, что если бы вы хотели получить список пар (значение, ключ) вместо этого? Подсказка: используйте zip().
>>> pricelist = list(zip(prices.values(),prices.keys()))
>>> pricelist
[(490.1, 'GOOG'), (23.45, 'AA'), (91.1, 'IBM'), (34.23, 'MSFT')]
>>>
Зачем это делать? Во-первых, это позволяет выполнять определенные виды обработки данных над данными словаря.
>>> min(pricelist)
(23.45, 'AA')
>>> max(pricelist)
(490.1, 'GOOG')
>>> sorted(pricelist)
[(23.45, 'AA'), (34.23, 'MSFT'), (91.1, 'IBM'), (490.1, 'GOOG')]
>>>
Это также иллюстрирует важную особенность кортежей. При использовании в сравнениях кортежи сравниваются элемент за элементом, начиная с первого элемента. Подобно тому, как строки сравниваются по символам.
zip() часто используется в таких ситуациях, когда нужно сопоставить данные из разных источников. Например, сопоставить имена столбцов с значениями столбцов, чтобы создать словарь именованных значений.
Обратите внимание, что zip() не ограничивается парами. Например, можно использовать его с любыми количеством входных списков:
>>> a = [1, 2, 3, 4]
>>> b = ['w', 'x', 'y', 'z']
>>> c = [0.2, 0.4, 0.6, 0.8]
>>> list(zip(a, b, c))
[(1, 'w', 0.2), (2, 'x', 0.4), (3, 'y', 0.6), (4, 'z', 0.8))]
>>>
Также обратите внимание, что zip() останавливается, как только исчерпан самая короткая входная последовательность.
>>> a = [1, 2, 3, 4, 5, 6]
>>> b = ['x', 'y', 'z']
>>> list(zip(a,b))
[(1, 'x'), (2, 'y'), (3, 'z')]
>>>
Поздравляем! Вы завершили лабораторную работу по последовательностям. Вы можете практиковаться в других лабораторных работах в LabEx, чтобы улучшить свои навыки.