Кортеж в питоне – Кортежи. Урок 20 курса «Python. Введение в программирование»

Кортежи. Урок 20 курса «Python. Введение в программирование»

Кортежи (tuple) в Python – это те же списки за одним исключением. Кортежи неизменяемые структуры данных. Так же как списки они могут состоять из элементов разных типов, перечисленных через запятую. Кортежи заключаются в круглые, а не квадратные.

>>> a = (10, 2.13, "square", 89, 'C')
>>> a
(10, 2.13, 'square', 89, 'C')

Из кортежа можно извлекать элементы и брать срезы:

>>> a[3]
89
>>> a[1:3]
(2.13, 'square')

Однако изменять его элементы нельзя:

>>> a[0] = 11
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Также у типа tuple нет методов для добавления и удаления элементов.

Возникает резонный вопрос. Зачем в язык программирования был введен этот тип данных, по-сути представляющий собой неизменяемый список? Дело в том, что иногда надо защитить список от изменений. Преобразовать же кортеж в список, если это потребуется, как и выполнить обратную операцию легко с помощью встроенных в Python функций list() и tuple():

>>> a = (10, 2.13, "square", 89, 'C')
>>> b = [1, 2, 3]
>>> c = list(a)
>>> d = tuple(b)
>>> c
[10, 2.13, 'square', 89, 'C']
>>> d
(1, 2, 3)

Рассмотрим случай, когда уместно использовать кортежи. В Python изменяемые объекты передаются в функцию по ссылке. Это значит, что не создается копия объекта, а переменной-параметру присваивается ссылка на уже существующий объект. В итоге, если в теле функции объект изменяется, то эти изменения касаются глобального объекта.

def addNum(seq, num):
    for i in range(len(seq)):
        seq[i] += num
    return seq
 
origin = [3, 6, 2, 6]
changed = addNum(origin, 3)
 
print(origin)
print(changed)

Данная программа неправильная. Хотя никаких выбросов исключений не произойдет, она содержит логическую ошибку. На выводе получаем:

[6, 9, 5, 9]
[6, 9, 5, 9]

То есть исходный список был также изменен. Параметр seq содержал ссылку не на свой локальный список, а на список-оригинал. Таким образом, в операторе return здесь нет смыла. Если функция замысливалась как изменяющая глобальный список, то программа должна выглядеть так:

def addNum(seq, num):
    for i in range(len(seq)):
        seq[i] += num
 
origin = [3, 6, 2, 6]
addNum(origin, 3)
print(origin)

Что делать, если все же требуется не изменять исходный список, а сформировать по нему новый. Задачу можно решить несколькими способами. Во первых, в функции можно создать локальный список, после чего возвращать его:

def addNum(seq, num):
    new_seq = []
    for i in seq:
        new_seq.append(i + num)
    return new_seq
 
origin = [3, 6, 2, 6]
changed = addNum(origin, 3)
 
print(origin)
print(changed)

Результат:

[3, 6, 2, 6]
[6, 9, 5, 9]

Исходный список в функции не меняется. Его элементы лишь перебираются.

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

Хотя преобразовывать к кортежу можно как при передаче в функцию, так и в самой функции, лучше сразу делать глобальный список кортежем. Поскольку неизменяемые объекты передаются по значению, а не по ссылке, то в функцию будет поступать копия структуры, а не оригинал. Даже если туда передается оригинал, изменить его невозможно. Можно лишь, как вариант, скопировать его и/или изменить тип, создав тем самым локальную структуру, и делать с ней все, что заблагорассудится.

def addNum(seq, num):
    seq = list(seq)
    for i in range(len(seq)):
        seq[i] += num
    return seq
 
origin = (3, 6, 2, 6)
changed = addNum(origin, 3)
 
print(origin)
print(changed)

Списки в кортежах

Кортежи могут содержать списки, также как списки быть вложенными в другие списки.

>>> nested = (1, "do", ["param", 10, 20])

Как вы думаете, можем ли мы изменить список [«param», 10, 20] вложенный в кортеж nested? Список изменяем, кортеж – нет. Если вам кажется, что нельзя, то вам кажется неправильно. На самом деле можно:

>>> nested[2][1] = 15
>>> nested
(1, 'do', ['param', 15, 20])

Примечание. Выражения типа nested[2][1] используются для обращения к вложенным объектам. Первый индекс указывает на позицию вложенного объекта, второй – индекс элемента внутри вложенного объекта. Так в данном случае сам список внутри кортежа имеет индекс 2, а элемент списка 10 – индекс 1 в списке.

Странная ситуация. Кортеж неизменяем, но мы все-таки можем изменить его. На самом деле кортеж остается неизменяемым. Просто в нем содержится не сам список, а ссылка на него. Ее изменить нельзя. Но менять сам список можно.

Чтобы было проще понять, перепишем кортеж так:

>>> l = ["param", 10, 20]
>>> t = (1, "do", l)
>>> t
(1, 'do', ['param', 10, 20])

Кортеж содержит переменную-ссылку. Поменять ее на другую ссылку нельзя. Но кортеж не содержит самого списка. Поэтому его можно менять как угодно:

>>> l.pop(0)
'param'
>>> t
(1, 'do', [10, 20])

Однако помните, такой номер не прокатывает с неизменяемыми типами:

>>> a = "Kat"
>>> t = (a, l)
>>> t
('Kat', [10, 20])
>>> a = "Bat"
>>> t
('Kat', [10, 20])

Они передаются в кортеж как и в функцию – по значению. Т. е. их значение копируется в момент передачи.

Практическая работа

  1. Чтобы избежать изменения исходного списка, не обязательно использовать кортеж. Можно создать его копию с помощью метода списка copy() или взять срез от начала до конца [:]. Скопируйте список первым и вторым способом и убедитесь, что изменение копий никак не отражается на оригинале.

  2. Заполните один кортеж десятью случайными целыми числами от 0 до 5 включительно. Также заполните второй кортеж числами от -5 до 0. Для заполнения кортежей числами напишите одну функцию. Объедините два кортежа с помощью оператора +, создав тем самым третий кортеж. С помощью метода кортежа count() определите в нем количество нулей. Выведите на экран третий кортеж и количество нулей в нем.

Примеры решения в android-приложении и pdf-версии курса.

younglinux.info

Основы Python — кратко. Часть 3. Списки, кортежи, файлы. / Habr

В общем-то последняя из готовых глав. Остальные будут выходить чуть реже, поскольку еще не написаны (но я уверен что будут, хотя это зависит только от ваших пожеланий, уважаемые читатели 🙂

Также следует заметить что это это, видимо, последний «простой урок», дальше я постараюсь углубиться во все аспекты программирования, которые мы прошли «по верхам» и продолжить более детально.

В общем, те кому не интересно — читают следующую новость, а остальных — прошу пройти .

Python для начинающих. Глава третья. «List, tuple, etc.»

Кортежи.

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

>>> t = (2, 2.05, "Hello")
>>> t
(2, 2.0499999999999998, 'Hello')
>>> (a, b, c) = t
>>> print a, b, c
2 2.05 Hello
>>> z, y, x = t
>>> print z, y, x
2 2.05 Hello
>>> a=1
>>> b=2
>>> a,b=b,a
>>> print a,b
2 1
>>> x = 12,
>>> x
(12,)

Как видно из примера, кортеж может быть использован и в левой части оператора присваивания. Значения из кортежа в левой части оператора присваивания связываются с аналогичными элементами правой части. Этот факт как раз и дает нам такие замечательные возможности как массовая инициализация переменных и возврат множества значений из функции одновременно. Последний пример демонстрирует создание кортежа из одного элмента (его часто называют синглтоном).

Списки

В Пайтоне отсутствуют массивы в традиционном понимании этого термина. Вместо них для хранения однородных (и не только) объектов используются списки. Они задаются тремя способами.

Простое перечисление:

>>> a = [2, 2.25, "Python"]
>>> a
[2, 2.25, 'Python']

Преобразуем строку в список

>>> b = list("help")
>>> b
['h', 'e', 'l', 'p']

Создание с помощью списковых включений. В данном случае мы берем кубы всех нечетных чисел от 0 до 19. Этому синтаксису я планирую посвятить отдельное занятие.

>>> c = [x ** 3 for x in range(20) if x%2==1]
>>> c
[1, 27, 125, 343, 729, 1331, 2197, 3375, 4913, 6859]

Для работы со списками определен ряд операторов и функций:
len(s) Длина последовательности s
x in s Проверка принадлежности элемента последовательности. В новых версиях Python можно проверять принадлежность подстроки строке. Возвращает True или False
x not in s = not x in s
s + s1 Конкатенация последовательностей
s*n или n*s Последовательность из n раз повторенной s. Если n
s[i] Возвращает i-й элемент s или len(s)+i-й, если i
s[i:j:d] Срез из последовательности s от i до j с шагом d будет рассматриваться ниже
min(s) Наименьший элемент s
max(s) Наибольший элемент s
s[i] = x i-й элемент списка s заменяется на x
s[i:j:d] = t Срез от i до j (с шагом d) заменяется на (список) t
del s[i:j:d] Удаление элементов среза из последовательности

Кроме того, для списков определен ряд методов.
append(x) Добавляет элемент в конец последовательности
count(x) Считает количество элементов, равных x
extend(s) Добавляет к концу последовательности последовательность s
index(x) Возвращает наименьшее i, такое, что s[i] == x. Возбуждает исключение ValueError, если x не найден в s
insert(i, x) Вставляет элемент x в i-й промежуток
pop(i) Возвращает i-й элемент, удаляя его из последовательности
reverse() Меняет порядок элементов s на обратный
sort([cmpfunc]) Сортирует элементы s. Может быть указана своя функция сравнения cmpfunc

Для преобразования кортежа в список есть функция list, для обратной операции — tuple.

Об индексировании списков и выделении подпоследовательностей следует еще раз упомянуть отдельно (этот механизм работает аналогично и для строк). Для получения элемента используются квадратные скобки, в которых находится индекс элемента. Элементы нумеруются с нуля. Отрицательное значение индекса указывает на элементы с конца. Первый с конца списка (строки) элемент имеет индекс -1.

>>> s = [0, 1, 2, 3, 4]
>>> print s[0], s[-1], s[3]
0 4 3
>>> s[2] = -2
>>> print s
[0, 1, -2, 3, 4]
>>> del s[2]
>>> print s
[0, 1, 3, 4]

Сложнее обстоят дела со срезами. Для получения срезов последовательности в Пайтоне принято указывать не номера элементов, а номера «промежутков» между ними. Перед первым элементом последовательности промежуток имеет индекс 0, перед вторым – 1 и так далее. Отрицательные значения отсчитывают элементы с конца строки.
В общем виде срез записывается в следующем виде:
список[начало: конец: шаг]
По умолчанию начало среза равно 0, конец среза равен len(список), шаг равен 1. Если шаг не указывается, второй символ «:» можно опустить.
С помощью среза можно указать подмножество для вставки списка в другой список, даже при нулевой длине. Это удобно для вставки списка в строго определенной позиции.

>>> l = range(12)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> l[1:3]
[1, 2]
>>> l[-1:]
[11]
>>> l[::2]
[0, 2, 4, 6, 8, 10]
>>> l[0:1]=[-1,-1,-1]
>>> l
[-1, -1, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> del l[:3]
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

Словари

Словарь (хэш, предопределенный массив) – изменяемая структура данных, предназначенная для хранения элементов вида ключ: значение. Все легко показывается на примере.

Создаем хеши.

>>> h2 = {1:"one", 2:"two", 3:"three"}
>>> h3 = {0:"zero", 5:"five"}
>>> h4 = {"z":1, "y":2, "x":3}
#Цикл по паре ключ-значение
>>> for key, value in h2.items():
...     print key, " ", value
...
1   one
2   two
3   three

#Цикл по ключам
>>> for key in h3.keys():
...     print key, " ", h3[key]
...
0   zero
5   five

#Цикл по значениям
>>> for v in h4.values():
...     print v
...
2
3
1

#Добавление элементов из другого хеша
>>> h2.update(h4)

#Количество пар в хеше
>>> len(h2)
6

Тип file

Объекты этого типа предназначены для работы с внешними данными. Чаще всего данному объекту соответствует файл на диске, но это далеко не всегда так. Файловые объекты должны поддерживать основные методы: read(), write(), readline(), readlines(), seek(), tell(), close() и т.п.

Следующий пример показывает копирование файла:

f1 = open("file1.txt", "r")
f2 = open("file2.txt", "w")
for line in f1.readlines():
  f2.write(line)
f2.close()
f1.close()

(этот пример можно записать массой других способов, многие из которых сильно отличаются по оптимальности, но это тоже тема отдельного разговора)

В принципе, большинству функций абсолютно безразлично, передан им объект типа файл, или любой другой объект с такими же методами. Так, приведенный выше пример можно очень легко модифицировать для скачивания файла из Интерне, заменив в нем первую строку на следующий код.

import urllib
f1 = urllib.urlopen("http://python.onego.ru") 

Задачи:
— Разработать программу «массовой закачки» URL-ов из файла urls.txt
— Разработать программу, скачивающую страницу по указанному URL со всем ее содержимым.
— Написать программу, которая получив на входе произвольный список удалит из него все повторяющиеся элементы.

habr.com

Именованные кортежи. Пишем код на Python чище / Habr

В стандартной библиотеке питона содержится специализированный тип «namedtuple», который, кажется, не получает того внимания, которое он заслуживает. Это одна из прекрасных фич в питоне, которая скрыта с первого взгляда.

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

Так что же такое именованный кортеж и что делает его таким специализированным? Хороший способ поразмышлять над этим — рассмотреть именованные кортежи как расширение над обычными кортежами.

Кортежи в питоне представляют собой простую структуру данных для группировки произвольных объектов. Кортежи являются неизменяемыми — они не могут быть изменены после их создания.

>>> tup = ('hello', object(), 42)
>>> tup
('hello', <object object at 0x105e76b70>, 42)
>>> tup[2]
42
>>> tup[2] = 23
TypeError: "'tuple' object does not support item assignment"

Обратная сторона кортежей — это то, что мы можем получать данные из них используя только числовые индексы. Вы не можете дать имена отдельным элементам сохранённым в кортеже. Это может повлиять на читаемость кода.

Также, кортеж всегда является узкоспециализированной структурой. Тяжело обеспечить, что бы два кортежа имели одни и те же номера полей и одни и те же свойства сохранённые в них. Это делает их лёгкими для знакомства со “slip-of-the-mind” багами, где легко перепутать порядок полей.

Цель именованных кортежей — решить эти две проблемы.

Прежде всего, именованные кортежи являются неизменяемыми подобно обычным кортежам. Вы не можете изменять их после того, как вы что-то поместили в них.

Кроме этого, именованные кортежи это, эм…, именованные кортежи. Каждый объект сохраненный в них может быть доступен через уникальный, удобный для чтения человеком, идентификатор. Это освобождает вас от запоминания целочисленных индексов или выдумывания обходных путей типо определения целочисленных констант как мнемоник для ваших индексов.

Вот как выглядит именованный кортеж:

>>> from collections import namedtuple
>>> Car = namedtuple('Car' , 'color mileage')

Чтобы использовать именованный кортеж, вам нужно импортировать модуль collections. Именованные кортежи были добавлены в стандартную библиотеку в Python 2.6. В примере выше мы определили простой тип данных «Car» с двумя полями: «color» и «mileage».

Вы можете найти синтакс немного странным здесь. Почему мы передаём поля как строку закодированную с «color mileage»?

Ответ в том, что функция фабрики именованных кортежей вызывает метод split() на строки с именами полей. Таким образом, это, действительно, просто сокращение, что бы сказать следующее:

>>> 'color mileage'.split()
['color', 'mileage']
>>> Car = namedtuple('Car', ['color', 'mileage'])

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

>>> Car = namedtuple('Car', [
...     'color',
...     'mileage',
... ])

Как бы вы ни решили, сейчас вы можете создать новые объекты «car» через фабричную функцию Car. Поведение будет такое же, как если бы вы решили определить класс Car вручную и дать ему конструктор принимающий значения «color» и «mileage»:

>>> my_car = Car('red', 3812.4)
>>> my_car.color
'red'
>>> my_car.mileage
3812.4

Распаковка кортежей и оператор ‘*’ для распаковки аргументов функций также работают как ожидается:

>>> color, mileage = my_car
>>> print(color, mileage)
red 3812.4
>>> print(*my_car)
red 3812.4

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

>>> my_car[0]
'red'
>>> tuple(my_car)
('red', 3812.4)

Вы даже можете получить красивое строковое отображение объектов бесплатно, что сэкономит вам время и спасёт от избыточности:

>>> my_car
Car(color='red' , mileage=3812.4)

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

>>> my_car.color = 'blue'
AttributeError: "can't set attribute"

Объекты именованных кортежей внутренне реализуются в питоне как обычные классы. Когда дело доходит до использованию памяти, то они так же «лучше», чем обычные классы и просто так же эффективны в использовании памяти как и обычные кортежи.

Хороший путь судить о них — считать, что именованные кортежи являются краткой формой для создания вручную эффективно работающего с памятью неизменяемого класса.

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

>>> Car = namedtuple('Car', 'color mileage')
>>> class MyCarWithMethods(Car):
...     def hexcolor(self):
...         if self.color == 'red':
...            return '#ff0000'
...         else:
...             return '#000000'

Сейчас мы можем создать объекты MyCarWithMethods и вызвать их метод hexcolor() так, как ожидалось:

>>> c = MyCarWithMethods('red', 1234)
>>> c.hexcolor()
'#ff0000'

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

Например, добавление нового неизменяемого поля является каверзной операцией из-за того как именованные кортежи устроены внутри. Более простой путь создания иерархии именованных кортежей — использование свойства ._fields базового кортежа:

>>> Car = namedtuple('Car', 'color mileage')
>>> ElectricCar = namedtuple(
...     'ElectricCar', Car._fields + ('charge',))

Это даёт желаемый результат:

>>> ElectricCar('red', 1234, 45.0)
ElectricCar(color='red', mileage=1234, charge=45.0)

Кроме свойства _fields каждый экземпляр именованного кортежа также предоставляет ещё несколько вспомогательных методов, которые вы можете найти полезными. Все их имена начинаются со знака подчёркивания, который говорит нам, что метод или свойство «приватное» и не является частью устоявшегося интерфейса класса или модуля.

Что касается именованных кортежей, то соглашение об именах начинающихся со знака подчёркивания здесь имеет другое значение: эти вспомогательные методы и свойства являются частью открытого интерфейса именованных кортежей. Символ подчёркивания в этих именах был использован для того, чтобы избежать коллизий имён с полями кортежа, определёнными пользователем. Так что, не стесняйтесь использовать их, если они вам понадобятся!

Я хочу показать вам несколько сценариев где вспомогательные методы именованного кортежа могут пригодиться. Давайте начнём с метода _asdict(). Он возвращает содержимое именованного кортежа в виде словаря:

>>> my_car._asdict()
OrderedDict([('color', 'red'), ('mileage', 3812.4)])

Это очень здорово для избегания опечаток при создании JSON, например:

>>> json.dumps(my_car._asdict())
'{"color": "red", "mileage": 3812.4}'

Другой полезный помощник — функция _replace(). Она создаёт поверхностную(shallow) копию кортежа и разрешает вам выборочно заменять некоторые поля:

>>> my_car._replace(color='blue')
Car(color='blue', mileage=3812.4)

И, наконец, метод класса _make() может быть использован чтобы создать новый экземпляр именованного кортежа из последовательности:

>>> Car._make(['red', 999])
Car(color='red', mileage=999)

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

Я нахожу, например, что путь от узкоспециализированных структур данных с жёстко заданным форматом, таких как словари к именованным кортежам помогает мне выражать мои намерения более чисто. Часто когда я пытаюсь это рефакторить, то я магически достигаю лучших решений проблем, с которыми я сталкиваюсь.

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

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

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

  • collections.namedtuple — краткая форма для создания вручную эффективно работающего с памятью неизменяемого класса.
  • Именованные кортежи могут помочь сделать ваш код чище, обеспечивая вас более простыми в понимании структурами данных.
  • Именованные кортежи предоставляют несколько полезных вспомогательных методов которые начинаются с символа подчёркивания (_), но являются частью открытого интерфейса. Использовать их — это нормальная практика.

habr.com

Упаковка данных в Python — кортеж tuple

Представьте себя функцией. Да, это не просто, и все же…

Вас зовут get_contacts и вы умеете находить контакты человека по email-адресу: его адрес, имя и номер телефона. Вы не прочь поделиться информацией с другими, но Python вам это запрещает. Нельзя возвращать так много данных разом, результат у функции может быть только один. Вы можете выбрать что-то одно, самое важное: адрес, имя, или телефон человека. Или можете проявить изобретательность и упаковать все свои данные в одну переменную.

Как упаковать

Для функции get_contacts(email) доступны несколько способов упаковки данных в более сложную структуру: словарь dict(), кортеж tuple() и еще несколько других. Рассмотрим подробнее последний вариант — tuple.

Предположим, вы вызвали функцию get_contacts('[email protected]'), она нашла такого человека и хочет вернуть его контакты:

full_name = 'Никифоров Дмитрий Анатольевич'
city = 'Москва'
phone_number = '929-876-54-32'

Функция создает кортеж — tuple() —, чтобы поместить в него все контакты:

contacts = (full_name, city, phone_number)

Круглые скобки и запятые указывают Python, что из перечисленных переменных full_name, city и phone_number нужно создать новую структуру данных:

print(type(contacts))  # выведет <class 'tuple'>
print(contacts)

Последний вызов print() выведет на экран такое:

('Никифоров Дмитрий Анатольевич', 'Москва', '929-876-54-32')

Теперь функция get_contacts сможет вернуть любое количество данных. Все они будут упакованы в один кортеж — tuple.

Что делать, если получили tuple

Разберем как работать с tuple на примере стандартной функции divmod. Она возвращает результат деления с остатком:

divmod(100, 3)  # выведет (33, 1)
divmod(2, 3) # выведет (0, 2)

Функция divmod возвращает кортеж из двух чисел — результата целочисленного деления и остаток от деления.

Мы можем сохранить результат в переменную:

div_tuple = divmod(100, 3)
print(div_tuple)  # выведет (33, 1)

Добраться до каждого из двух чисел можно по индексу:

div_tuple = divmod(100, 3)
print(div_tuple[0])  # выведет 33
print(div_tuple[1])  # выведет 1

Индексы в коде [0] и [1] сильно осложняют чтение, поэтому полезно давать говорящие названия:

div_tuple = divmod(100, 3)
int_division = div_tuple[0]
remainder = div_tuple[1]

print(int_division)  # выведет 33
print(remainder)  # выведет 1

Такой паттерн рекомендуется к использованию и встречается настолько часто, что в Python ввели упрощенную короткую запись:

(int_division, remainder) = divmod(100, 3)
print(int_division)  # выведет 33
print(remainder)  # выведет 1

Запись похожа на создание кортежа — те же скобки и запятые, но работает это в обратную сторону. Называется «распаковкой».

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

int_division, remainder = divmod(100, 3)
print(int_division)  # выведет 33
print(remainder)  # выведет 1

Последняя форма записи распаковки наиболее распространена и рекомендуется к использованию.

Скобки не обязательно указывать и при создании кортежа, но этот прием может усложнить чтение кода, будьте с ним осторожны:

contacts = full_name, city, phone_number

В коде внутри функций часто встречается еще более короткая запись:

return full_name, city, phone_number

Вызов return сообщает интерпретатору Python, что функция завершает свою работу и хочет вернуть результат. А все перечисленное справо от return будет упаковано в кортеж — tuple.

Ссылки по теме:

devman.org

Про Python — Справочник — tuple (кортеж)

Кортеж — неизменяемая последовательность с упорядоченными элементами.

Элементами кортежей могут выступать любые объекты.

Объявление

В коде кортежи могут быть объявлены при помощи скобок — () — внутри скобок через запятую перечисляются элементы в нужной последовательности. Если кортеж состоит из одного элемента при объявлении требуется поставить запятую после этого элемента.

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

    my_empty_tuple = ()

my_tuple = 1, 'some', 3.5 # то же, что и (1, 'some', 3.5)
my_tuple = 'a', # то же, что и ('a',)

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

    tuple() # ()
tuple('abc') # ('a', 'b', 'c')
tuple([1, 2, 3]) # (1, 2, 3)

Сравнение

Два картежа сравниваются лексикографически: считаются равными, если имеют одинаковую длину и равны их соответствующие элементы:

    a = (3, 2, 1)
b = (1, 2, 3)
d = (3, 2, 2)
e = (3, 2)
f = (3, 2, 'a')
a > b # True
a > d # False
d > b # True
a > e # True
# Python 3
a > f # TypeError: '>' not supported between instances of 'int' and 'str'
# Python 2
a > f # False

Детали реализации CPython

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

  a = ()
b = ()
a is b # True
id(a) == id(b) # True

При удалении кортежа (например, с помощью del, или сборщика мусора) небольшой длины (не более 19 элементов), он не удалется сразу, а перемещается в очередь удаления. Эта очередь имеет 20 групп, в каждую из которых помещаются удалённые кортежи соответствующей длины, причём в первой группе хранится пустой кортеж.

    tuple_0 = (1, 2, 3)
print('tuple_0 %s' % id(tuple_0)) # 140332152236648

tuple_1 = (1, 2, 3)
print('tuple_1 %s' % id(tuple_1)) # 140332152236720

del tuple_1
# Далее предполагается, что сборка мусора уже прошла.
# Проще всего наблюдать за работой из интерактивного сеанса
# интерпретатора.

tuple_2 = (1, 2, 4)
print('tuple_2 %s' % id(tuple_2)) # 140332152236720

Синонимы поиска: кортеж, кортежи, cortege, typle, тупл

pythonz.net

Python: изменение значения в кортеже — python

Ну, как уже показало Trufa, в принципе есть два способа замены элемента кортежа на данный индекс. Либо преобразовать кортеж в список, заменить элемент и преобразовать обратно, либо построить новый кортеж путем конкатенации.

In [1]: def replace_at_index1(tup, ix, val):
   ...:     lst = list(tup)
   ...:     lst[ix] = val
   ...:     return tuple(lst)
   ...:

In [2]: def replace_at_index2(tup, ix, val):
   ...:     return tup[:ix] + (val,) + tup[ix+1:]
   ...:

Итак, какой метод лучше, то есть быстрее?

Оказывается, что для коротких кортежей (на Python 3.3) конкатенация выполняется быстрее!

In [3]: d = tuple(range(10))

In [4]: %timeit replace_at_index1(d, 5, 99)
1000000 loops, best of 3: 872 ns per loop

In [5]: %timeit replace_at_index2(d, 5, 99)
1000000 loops, best of 3: 642 ns per loop

Однако, если мы посмотрим на более длинные кортежи, конвертирование списка — это способ:

In [6]: k = tuple(range(1000))

In [7]: %timeit replace_at_index1(k, 500, 99)
100000 loops, best of 3: 9.08 µs per loop

In [8]: %timeit replace_at_index2(k, 500, 99)
100000 loops, best of 3: 10.1 µs per loop

Для очень длинных кортежей преобразование списков значительно лучше!

In [9]: m = tuple(range(1000000))

In [10]: %timeit replace_at_index1(m, 500000, 99)
10 loops, best of 3: 26.6 ms per loop

In [11]: %timeit replace_at_index2(m, 500000, 99)
10 loops, best of 3: 35.9 ms per loop

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

In [12]: %timeit replace_at_index1(m, 900000, 99)
10 loops, best of 3: 26.6 ms per loop

In [13]: %timeit replace_at_index2(m, 900000, 99)
10 loops, best of 3: 49.2 ms per loop

Итак: если ваш кортеж короток, нарежьте и соедините.
Если он длинный, выполните преобразование списка!

qaru.site

Преобразование кортежа в список и обратно Ru Python

В настоящее время я работаю над редактором карт для игры в pygame, используя карты плитки. Уровень строится из блоков в следующей структуре (хотя и намного больше):

где «1» – это блок, который представляет собой стену, а «0» – это блок, который является пустым воздухом.

Следующий код, в основном, относится к изменению типа блока:

Но поскольку уровень хранится в кортеже, я не могу изменить значения разных блоков. Как я могу легко изменить различные значения на уровне?

Преобразовать кортеж в список:

 >>> t = ('my', 'name', 'is', 'mr', 'tuple') >>> t ('my', 'name', 'is', 'mr', 'tuple') >>> list(t) ['my', 'name', 'is', 'mr', 'tuple'] 

Преобразовать список в кортеж:

 >>> l = ['my', 'name', 'is', 'mr', 'list'] >>> l ['my', 'name', 'is', 'mr', 'list'] >>> tuple(l) ('my', 'name', 'is', 'mr', 'list') 

У вас есть кортеж кортежей.
Чтобы преобразовать каждый кортеж в список:

 [list(i) for i in level] # list of lists 

— ИЛИ —

 map(list, level) 

И после того, как вы закончите редактирование, просто преобразуйте их обратно:

 tuple(tuple(i) for i in edited) # tuple of tuples 

— ИЛИ — (Спасибо @jamylak)

 tuple(itertools.imap(tuple, edited)) 

Вы также можете использовать массив numpy:

 >>> a = numpy.array(level1) >>> a array([[1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1]]) 

Для управления:

 if clicked[0] == 1: x = (mousey + cameraY) // 60 # For readability y = (mousex + cameraX) // 60 # For readability a[x][y] = 1 

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

 level1 = [list(row) for row in level1] 

или

 level1 = map(list, level1) 

и соответственно модифицировать их.

Но массив numpy более холодный.

Преобразование кортежей в список

(Запятые отсутствовали между кортежами в заданном вопросе, он был добавлен для предотвращения сообщения об ошибке)

Способ 1:

 level1 = ( (1,1,1,1,1,1), (1,0,0,0,0,1), (1,0,0,0,0,1), (1,0,0,0,0,1), (1,0,0,0,0,1), (1,1,1,1,1,1)) level1 = [list(row) for row in level1] print(level1) 

Способ 2:

 level1 = map(list,level1) print(list(level1)) 

Метод 1 принимал — 0.0019991397857666016 секунд —

Метод 2 взял — 0.0010001659393310547 секунд —

Почему бы вам не попробовать преобразовать свой тип из кортежа в список и наоборот.

 level1 = ( (1,1,1,1,1,1) (1,0,0,0,0,1) (1,0,0,0,0,1) (1,0,0,0,0,1) (1,0,0,0,0,1) (1,1,1,1,1,1)) print(level1) level1 = list(level1) print(level1) level1 = tuple(level1) print(level1) 

Оба ответа хороши, но небольшой совет:

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

В вашем случае извлеките данные в список, как показано eumiro, и после изменения создайте аналогичный кортеж аналогичной структуры, как ответ, данный Школьником.

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

Вы могли бы значительно ускорить работу, если бы вы использовали только один список, а не список списков. Это возможно, конечно, только если все ваши внутренние списки имеют одинаковый размер (что верно в вашем примере, поэтому я просто предполагаю это).

 WIDTH = 6 level1 = [ 1,1,1,1,1,1, 1,0,0,0,0,1, 1,0,0,0,0,1, 1,0,0,0,0,1, 1,0,0,0,0,1, 1,1,1,1,1,1 ] print level1[x + y*WIDTH] # print value at (x,y) 

И вы могли бы быть еще быстрее, если бы вместо бинарного поля вместо списка:

 WIDTH = 8 # better align your width to bytes, eases things later level1 = 0xFC84848484FC # bit field representation of the level print "1" if level1 & mask(x, y) else "0" # print bit at (x, y) level1 |= mask(x, y) # set bit at (x, y) level1 &= ~mask(x, y) # clear bit at (x, y) 

с

 def mask(x, y): return 1 << (WIDTH-x + y*WIDTH) 

Но это работает только в том случае, если ваши поля содержат только 0 или 1. Если вам нужно больше значений, вам придется

www.rupython.com

Отправить ответ

avatar
  Подписаться  
Уведомление о