1.3 Noções Básicas de Padrões🔗
Porque usar padrões?🔗
Os objetos Player utilizam listas Python, frequentemente conhecidas como arrays noutras linguagens de programação, para criar sequências de valores, como tom e duração. No entanto, as listas não são as estruturas de dados mais intuitivas para transformações. Por exemplo, tente multiplicar uma lista – o que acontece?
The result is the same list repeated twice! If you want to manipulate the internal values (e.g. double them) in Python, then here’s how you might do it:
O resultado é a mesma lista repetida duas vezes! Se quiser manipular os valores internos (por exemplo, duplicá-los) em Python, aqui está como pode fazê-lo:
values = [1, 2, 3]
# Use a loop
my_list = []
for i in values:
my_list.append(i * 2)
print(my_list)
# List comprehension
print([i*2 for i in values])
Para ambos os métodos, é necessário percorrer todos os valores e multiplicar cada um individualmente. As coisas ficam ainda mais complicadas se também quiser multiplicar cada segundo valor por um número diferente. Isso requer bastante trabalho, especialmente se não souber quais números irá usar. É aqui que entra a classe Pattern.
Os padrões funcionam como listas Python normais, mas qualquer transformação matemática realizada neles é feita em cada item da lista. A maneira mais simples de criar um padrão é simplesmente adicionar um P maiúsculo no início de uma lista:
Agora, quando realizar uma operação, como multiplicação, obterá o padrão transformado:
Você também pode criar um padrão como criaria qualquer outro objeto Python, usando o nome da classe seguido de colchetes com parâmetros:
Os padrões também são "indexáveis por módulo", o que significa que, independentemente do valor que usamos como índice quando acessar os dados de um padrão, desde que seja um número inteiro, obtemos um valor de retorno. Se o índice for maior do que o comprimento do padrão, simplesmente voltamos ao início do padrão e começamos a procurar:
Transformações🔗
Você pode realizar uma operação em um padrão usando uma lista ou outro padrão para criar transformações mais complexas. Por exemplo, somar os padrões P[0, 1, 2, 3] e P[4, 7] executará a operação por sua vez, o que significa que o padrão resultante será P[0 + 4, 1 + 7, 2 + 4, 3 + 7], ou seja, P[4, 8, 6, 10]. Usar padrões de comprimentos sem divisor comum criará um novo padrão que contém todos os valores das combinações:
Os padrões também têm métodos específicos para transformação, como rodar, inverter e ordenar, que podem ser usados para manipular a ordem:
>>> P[4, 1, 3, 2].rotate()
P[1, 3, 2, 4]
>>> P[4, 1, 3, 2].reverse()
P[2, 3, 1, 4]
>>> P[4, 1, 3, 2].sort()
P[1, 2, 3, 4]
Você pode executar help(Pattern) para ver mais informações sobre os métodos.
Funções de Padrões🔗
Existem várias funções que retornam diferentes padrões. Estas geram padrões mais longos usando apenas alguns parâmetros. Para ver uma lista das funções de padrão, você pode executar help(Patterns.Sequences).
Em Python, você pode gerar um intervalo de números inteiros com a sintaxe range(start, stop, step). Por predefinição, start é 0 e step é 1. Você pode usar PRange(start, stop, step) para criar um objeto Pattern com os valores equivalentes:
E como essas instâncias retornam Pattern, podemos tratá-las como objetos Pattern e usar métodos Pattern e realizar operações aritméticas nelas, assim:
Concatenação de Padrões🔗
Em Python, você normalmente concatenaria duas listas (anexaria uma à outra) usando o operador +, mas já vimos que fazer isso com padrões adicionaria os valores de um padrão ao conteúdo de outro. Para concatenar dois objetos Pattern, pode usar o símbolo de pipe, |, com o qual os utilizadores Linux podem estar familiarizados – ele é usado para conectar programas de linha de comando, enviando a saída de um processo como entrada para outro.
Padrões entrelaçados e PGroups🔗
O que acontece quando um padrão contém uma lista aninhada como esta?
First of all, the nested list is converted into a pattern (and any nested lists it might have contained are also converted). If we try and access the nested pattern here is what happens:
Primeiro, a lista aninhada é convertida num padrão (e quaisquer listas aninhadas que ela possa conter também são convertidas). Se tentarmos acessar o padrão aninhado, eis o que acontece:
Isso é estranho...? Seria compreensível pensar que a última linha retornaria P[3, 5], pois esse é o objeto no terceiro slot de pat, mas não é assim que os padrões se comportam. Os padrões são entrelaçados, o que significa que os valores dos padrões aninhados são retornados quando o padrão pai é acessado. Para acessar o segundo valor do padrão aninhado no exemplo acima, precisamos percorrer o padrão uma segunda vez, ou seja, usar um valor de índice maior que o comprimento do padrão:
Por isso, ao imprimir o comprimento de um padrão, você verá o tamanho do padrão como se ele estivesse expandido, conforme mostrado acima. Se utilizar parênteses e aninhar uma tupla de valores, verá que algo muito diferente acontece:
O último item no padrão é conhecido como PGroup e é usado para manter os valores dentro de um padrão juntos, ou seja, não entrelaçados:
Agrupar valores significa que eles são reproduzidos ao mesmo tempo, o que é muito útil quando se deseja tocar notas juntas, por exemplo, acordes:
Você pode adicionar tuplas/PGroups a um padrão para criar um novo padrão de itens PGroup: