Mais

Até agora, cobrimos a maioria dos vários aspectos do Python que você usará. Neste capítulo, abordaremos mais alguns aspectos que tornarão nosso conhecimento do Python mais equilibrado.

Passando tuplas ao redor

Já desejou que você pudesse retornar dois valores diferentes de uma função? Você pode. Tudo o que você precisa fazer é usar uma tupla.

>>> def get_error_details():
...     return (2, 'details')
...
>>> errnum, errstr = get_error_details()
>>> errnum
2
>>> errstr
'details'

Observe que o uso de a, b = <some expression> interpreta o resultado da expressão como uma tupla com dois valores.

Isso também significa que a maneira mais rápida de trocar duas variáveis em Python é:

>>> a = 5; b = 8
>>> a, b
(5, 8)
>>> a, b = b, a
>>> a, b
(8, 5)

Métodos especiais

Existem certos métodos, como o __init__ and __del__ Métodos que têm significância especial nas aulas.

Métodos especiais são usados para imitar determinados comportamentos de tipos incorporados. Por exemplo, se você quiser usar o x[key] operação de indexação para a sua classe (assim como você a usa para listas e tuplas), então tudo que você precisa fazer é implementar a __getitem__() método e seu trabalho está pronto. Se você pensar sobre isso, isso é o que o Python faz para o list class itself!

Alguns métodos especiais úteis estão listados na tabela a seguir. Se você quer saber sobre todos os métodos especiais, veja o manual.

  • __init__(self, ...)

    • Este método é chamado apenas antes do objeto recém-criado retornar para uso.
  • __del__(self)

    • Chamado imediatamente antes do objeto ser destruído (o que tem um tempo imprevisível, então evite usar isso)
  • __str__(self)

    • Chamado quando usamos o print função ou quando str() é usado.
  • __lt__(self, other)

    • Chamado quando o menos que operador (<) é usado. Da mesma forma, existem métodos especiais para todos os operadores (+, >, etc.)
  • __getitem__(self, key)

    • Chamado quando x[key] operação de indexação é usada.
  • __len__(self)

    • Chamado quando o built-in len() a função é usada para o objeto de seqüência.

Blocos de declaração única

Vimos que cada bloco de declarações é separado do resto pelo seu próprio nível de indentação. Bem, há uma ressalva. Se o seu bloco de instruções contiver apenas uma única declaração, então você pode especificá-la na mesma linha, por exemplo, uma declaração condicional ou declaração de loop. O exemplo a seguir deve deixar isso claro:

>>> flag = True
>>> if flag: print('Yes')
...
Yes

Observe que a única instrução é usada no local e não como um bloco separado. Embora, você pode usar isso para fazer seu programa menor, Eu recomendo evitar este método de atalho, exceto para verificação de erros, principalmente porque será muito mais fácil adicionar uma indicação extra se você estiver usando um recuo adequado.

Formulários Lambda

Uma lambda declaração é usada para criar novos objetos de função. Essencialmente, o lambda leva um parâmetro seguido de uma única expressão. Lambda torna-se o corpo da função. O valor dessa expressão é retornado pela nova função.

Exemplo (salvar como more_lambda.py):

points = [{'x': 2, 'y': 3},
          {'x': 4, 'y': 1}]
points.sort(key=lambda i: i['y'])
print(points)

Saída:

$ python more_lambda.py
[{'y': 1, 'x': 4}, {'y': 3, 'x': 2}]

Como funciona

Observe que o sort método de list pode levar uma key parâmetro que determina como a lista é classificada (geralmente sabemos apenas sobre ordem ascendente ou decrescente). No nosso caso, queremos fazer um tipo personalizado, e para isso precisamos escrever uma função. Em vez de escrever um def bloquear uma função que se usará apenas neste único lugar, usamos uma expressão lambda para criar uma nova função.

Lista de Compreensão

As compreensões de lista são usadas para derivar uma nova lista de uma lista existente. Suponha que você tenha uma lista de números e você deseja obter uma lista correspondente com todos os números multiplicados por 2 somente quando o número em si for maior que 2. As compreensões de lista são ideais para tais situações.

Exemplo (salvar como more_list_comprehension.py):

listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
print(listtwo)

Saída:

$ python more_list_comprehension.py
[6, 8]

Como funciona

Aqui, derivamos uma nova lista especificando a manipulação a ser feita (2*i) quando alguma condição está satisfeita (if i > 2). Observe que a lista original permanece inalterada.

A vantagem de usar compreensões de lista é que reduz a quantidade de código de referência exigido quando usamos loops para processar cada elemento de uma lista e armazená-lo em uma nova lista.

Recebendo Tuplas e Dicionários em Funções

Existe uma maneira especial de receber parâmetros para uma função como uma tupla ou um dicionário usando o * ou ** prefixo, respectivamente. Isso é útil quando se toma um número variável de argumentos na função.

>>> def powersum(power, *args):
...     '''Return the sum of each argument raised to the specified power.'''
...     total = 0
...     for i in args:
...         total += pow(i, power)
...     return total
...
>>> powersum(2, 3, 4)
25
>>> powersum(2, 10)
100

Porque temos um * prefixo no args variável, todos os argumentos extra passados para a função são armazenados em args como uma tupla. Se um ** O prefixo havia sido usado em vez disso, os parâmetros extras seriam considerados pares de chave / valor de um dicionário.

A afirmação afirmativa

A assert declaração é usada para afirmar que algo é verdadeiro. Por exemplo, se você tiver certeza de que você terá pelo menos um elemento em uma lista que você está usando e deseja verificar isso, e levante um erro se não for verdade, então assert declaração é ideal nesta situação. Quando a declaração assert falhar, uma AssertionError é criada. O pop() método remove e retorna o último item da lista.

>>> mylist = ['item']
>>> assert len(mylist) >= 1
>>> mylist.pop()
'item'
>>> assert len(mylist) >= 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

A assert declaração deve ser usada judiciosamente. Na maioria das vezes, é melhor capturar exceções, lidar com o problema ou exibir uma mensagem de erro para o usuário e depois encerrar.

Decoradores

Os decoradores são um atalho para aplicar as funções do wrapper. Isso é útil para "embrulhar" a funcionalidade com o mesmo código uma e outra vez. Por exemplo, criei um retry decorador para mim que eu posso simplesmente aplicar a qualquer função e se qualquer exceção for jogada durante uma corrida, é novamente tentada, até um máximo de 5 vezes e com um atraso entre cada repetição. Isso é especialmente útil para situações em que você está tentando fazer uma chamada de rede para um computador remoto:

from time import sleep
from functools import wraps
import logging
logging.basicConfig()
log = logging.getLogger("retry")


def retry(f):
    @wraps(f)
    def wrapper_function(*args, **kwargs):
        MAX_ATTEMPTS = 5
        for attempt in range(1, MAX_ATTEMPTS + 1):
            try:
                return f(*args, **kwargs)
            except:
                log.exception("Attempt %s/%s failed : %s",
                              attempt,
                              MAX_ATTEMPTS,
                              (args, kwargs))
                sleep(10 * attempt)
        log.critical("All %s attempts failed : %s",
                     MAX_ATTEMPTS,
                     (args, kwargs))
    return wrapper_function


counter = 0


@retry
def save_to_database(arg):
    print("Write to a database or make a network call or etc.")
    print("This will be automatically retried if exception is thrown.")
    global counter
    counter += 1
    # This will throw an exception in the first call
    # And will work fine in the second call (i.e. a retry)
    if counter < 2:
        raise ValueError(arg)


if __name__ == '__main__':
    save_to_database("Some bad value")

Saída:

$ python more_decorator.py
Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.
ERROR:retry:Attempt 1/5 failed : (('Some bad value',), {})
Traceback (most recent call last):
  File "more_decorator.py", line 14, in wrapper_function
    return f(*args, **kwargs)
  File "more_decorator.py", line 39, in save_to_database
    raise ValueError(arg)
ValueError: Some bad value
Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.

Como funciona

See:

Diferenças entre Python 2 e Python 3

See:

Resumo

Cobrimos mais alguns recursos do Python neste capítulo e ainda não cobrimos todos os recursos do Python. No entanto, nesta fase, cobrimos a maior parte do que você vai usar na prática. Isso é suficiente para que você comece com qualquer programa que você vai criar.

Em seguida, vamos discutir como explorar Python ainda mais.