Chapter 2 - An array of sequences
Built-in sequences
Container sequências: armazena referências para os objetos que contém (aceita diferentes tipos)
list, tuple and collections.deque can hold items of different types.
Flat sequências:
str, bytes, bytearray, memoryview and array.array hold items of one type.
Mutabilidade
Mutable sequências
list, bytearray, array.array, collections.deque and memoryview
Immutable sequências
tuple, str and byte
List Comprehensions in Python (aka listcomps)
Often seen as a part of functional programming in Python, list comprehensions allow you to create lists with a for loop with less code.
normal way
my_list = []
for x in range(10):
my_list.append(x * 2)
print(my_list)
listcomps way
comp_list = [x * 2 for x in range(10)]
print(comp_list)
Listcomps x map
and filter
map
and filter
symbols = '$¢£¥€¤'
beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
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.
O que são generators?
Generators são uma forma simples de criarmos iteradores. Ele irá retornar um objeto (iterador) para que nós possamos iterar sobre este objeto (um valor de cada vez).
# generator expressions
def generator():
n = 1
print("Essa uma funcao Generator")
print(n)
yield n
n += 1
print(n)
yield n
n += 1
print(n)
yield n
a = generator()
next(a)
# 1
next(a)
# 2
next(a)
# 3
next(a)
# StopIteration - ERROR
É muito simples criar uma função Generator, mas existem algumas peculiaridades. Por exemplo, nós usamos a declaração yield
ao invés de return. Se a função contém ao menos uma declaração yield
então ela se torna uma função Generator.
O
yield
pode ser lido como um pause, que retorna um objeto do tipo generator.O objeto Generator só pode ser iterado uma única vez.
Generator expressions
As Generators Expressions facilitam à criação de Generators. Assim como uma função lambda cria uma função anônima, uma Generator Expression cria uma função Generator anônima. A sintaxe é bem parecida com as famosas List Comprehensions com o pequeno detalhe de que os colchetes [ ] são subsituídos pelos parênteses ().
O padrão da maioria dessas expressões é algo dessa forma:
genexpr = (expression for item in collection)
A expressão acima corresponde a função abaixo:
def generator():
for item in collection:
yield expression
Tuples
listas imutáveis
armazenar registros
Tuples para agrupar dados
julia = ("Julia", "Roberts", 1967, "Duplicity", 2009, "Actress", "Atlanta, Georgia")
Tuple assignment and unpacking (Atribuição múltipla)
O poder das tuplas está no unpacking mechanism. Unpacking é a separação de um tuple (ou qualquer sequência) em várias variáveis. Cada variável recebe um valor do tuple.
(name, surname, b_year, movie, m_year, profession, b_place) = julia
Parallel Assignment
>>> lax_coordinates = (33.9425, -118.408056)
>>> latitude, longitude = lax_coordinates # tuple unpacking
>>> latitude
33.9425
>>> longitude
-118.408056
Trocar os valores de 2 variáveis
Nesse caso, não precisa de um terceira variável temporária.
Antes:
temp = a a = b b = temp
Tuplas:
name, surname = surname, name
Podemos usar (*) to unpack tuple
Função retorna (2 , 4) um par de números que consiste em seu quociente e o resto da divisão.
divmod(20, 8)
# (2, 4)
Então, podemos tentar utilizar a tupla como parâmetro.
# criamos a tupla t
t = (20, 8)
divmod(t)
#TypeError: divmod expected 2 arguments, got 1
No entanto, a função divmod()
recebe 2 parâmetros e não apenas 1. Podemos desestrutura a tupla, utilizando simplesmente o caractere (*).
divmod(*t)
Além disso, já podemos usar o assingment:
quotient, remainder = divmod(*t)
print(quotient, remainder)
Namedtuple
Nesse caso, temos que passar para a função 2 parâmetros:
nome da classe
lista de campos
City = namedtuple('City', 'name country population coordinates')
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
tokyo.population
novos atributos
._fields
: exibe o nome dos campos da classe._make()
: pode instanciar uma namedtuple a partir de outra namedtuple.
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data)
>>> delhi
city(name='Delhi NCR', country='IN', population=21.935, coordinates=LatLong(lat=28.613889, long=77.208889))
._asdict()
: retornacollections.OrderedDict
exibindo também os campos da named tuple.
>>> delhi._asdict()
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])
Uso do * para capturar itens excedentes
>>> a, b, *rest = range(15)
>>> a, b, rest
(0, 1, [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> type(rest)
<class 'list'>
>>> type(a)
<class 'int'>
args e *kwargs
Antes de mais nada, eles não precisam se chamar args ou kwargs, mas precisam ter o e *, respectivamente! **Os nomes “args” são apenas uma convenção.
https://www.geeksforgeeks.org/args-kwargs-python/
*args exemplo
O interessante é que o *ags é lido como uma tupla, então podemos iterá-lo para pegar os valores.
# Python program to illustrate
# *args for variable number of arguments
def myFun(*args):
print(type(args))
for arg in args:
print (arg)
myFun('Hello', 'Welcome', 'to', 'GeeksforGeeks')
# <class 'tuple'>
# Hello
# Welcome
# to
# GeeksforGeeks
**kwargs exemplo
A diferença aqui é que não passamos somente uma tupla, mas uma lista de chave-valores.Então, nesse caso temo um dicionário.
# Python program to illustrate
# *kargs for variable number of keyword arguments
def myFun(**kwargs):
print(type(kwargs))
for key, value in kwargs.items():
print ("%s == %s" %(key, value))
# Driver code
myFun(first ='Geeks', mid ='for', last='Geeks')
# <class 'dict'>
# first == Geeks
# mid == for
# last == Geeks
Passar uma lista como parâmetro para uma função que recebe n
valores
n
valoresdef myFun(arg1, arg2, arg3):
print("arg1:", arg1)
print("arg2:", arg2)
print("arg3:", arg3)
Podemos passar a lista como parâmetro para invocar a função. usando *
# Now we can use *args or **kwargs to
# pass arguments to this function :
args = ("Geeks", "for", "Geeks")
myFun(*args)
Ou podemos passar uma lista chave-valor na qual as chaves devem ter o nome dos argumentos da função.
kwargs = {"arg1" : "Geeks", "arg2" : "for", "arg3" : "Geeks"}
myFun(**kwargs)
Slicing
https://www.youtube.com/watch?v=ajrtAuDg3yw
a[start:stop:step] # items start through start and skip numbers considering number passed on step
a[start:stop] # items start through stop-1
a[start:] # items start through the rest of the array
a[:stop] # items from the beginning through stop-1
a[:] # a copy of the whole array
list = ['Carla','Leonardo','Carlos']
#input
list[:2]
['Carla', 'Leonardo']
Multi-dimensional slicing and ellipsis
Assigning to slices
Podemos modificar (alterar valores, adicionar, substituir) sequências mutáveis utilizando slice.
l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Substituímos o valores nos índices 2, 3 e 4 por apenas 2 valores, reduzindo o tamanho da lista.
l[2:5] = [20, 30]
len(l)
>>> 19
l[2:5] = [115,120,123,125]
len(l)
>>> 21
Operations +
*
with sequences
+
*
with sequencesConcatenação de sequências
lista_1 = [1, 2, 3]
lista_2 = [4, 5, 6]
lista_1 + lista_2
>>> [1, 2, 3, 4, 5, 6]
Repetição
lista_1 * 2
>>> [1, 2, 3, 1, 2, 3]
Nessas operações novos objetos são criados.
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
id(my_list)
>>> 4561859520
my_list = my_list * 2
id(my_list)
>>> 4562997328
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
id(my_list)
>>> 4561859520
Building lists of lists
Correto
Uma lista que contém 3 listas de 4 itens cada
board = [['_'] * 4 for i in range(3)]
board
>>> [['_', '_', '_','_'], ['_', '_', '_','_'], ['_', '_', '_','_']]
board[1][2] = 'X'
board
>>> [['_', '_', '_','_'], ['_', '_', 'X','_'], ['_', '_', '_','_']]
Errado
Uma lista com 3 referêncis para mesma lista, o que não era nossa intenção.
weird_board = [['_'] * 3] * 3
weird_board
>>> [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
weird_board[1][2] = 'O'
weird_board
>>> [['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]
Operations +=
*=
with sequences
+=
*=
with sequences+=
invoca o método especial__iadd__
*=
invoca o método especial__imul__
Qual a diferença das operações em listas mutáveis e imutáveis?

Então, várias concatenações em listas imutáveis é ineficiente porque ao invés de apenas adicionar itens na lista, um novo objeto é criado com uma cópia do original.
A+= (corner case)

o interpretador consegue alterar o valor da lista
t[2]
, pois é uma listamas não consegue adicionar t[2] na lista
t
, poist
é uma tupla.
Dá para ver melhor com bytecode:

t=(1,2,[30,40])
type(t)
# <class 'tuple'>
type(t[2])
# <class 'list'>
type(t[0])
# <class 'int'>
Alguns aprendizados a partir disso:
não inserir items mutáveis dentro de uma tupla
+=
não é uma operação atômicaentender melhor o bytecode pode ser algo útil
list.sort
O método list.sort()
ordena a lista in-place - não cria uma cópia do objeto. Tanto que não podemos atribuí-lo para outra variável:
t = [10, 15, 20, 5]
t.sort()
x = t.sort()
t
# [5, 10, 15, 20]
type(x)
# <class 'NoneType'>
Convenção do Python: Funções ou métodos que alteram objetos in-place sempre retornam None
.
sorted function
Algoritmo de ordenação Timsort baseado no Insertion Sort e Merge sort.
A built-in functionsorted
cria uma nova lista e a retorna - possui 2 argumentos possíveis (reversed
ekey
).
t = [10, 15, 20, 5]
sorted(t)
# [5, 10, 15, 20]
x = sorted(t)
x
# [5, 10, 15, 20]
Bisect - binary search method in Python
Pode ser usado para buscar um elemento em uma lista.
Ex 1: nesse caso, a função bisect_left
retorna o índice da primeira ocorrência do elemento 285
.
import bisect
a = [-14,-10,2,108,108,285,285,285,401]
print(bisect.bisect_left(a, 285))
# 5
Ex 2: nesse caso, a função bisect_left
retorna o índice da última ocorrência do elemento 285
.
print(bisect.bisect_right(a, 285))
# 5
lo/hi arguments
bisect.insort
insort(seq, item)
- insere um item na sequência de forma a mantê-la ordenada de forma crescente.

Arrays
mais eficiente para listas com um único tipo
array(data type, value list)

append
insert
pop
remove
index
reverse
array.tofile()
array.tofile()
Memory views
Last updated
Was this helpful?