Dicas úteis sobre Python que você nunca conheceu antes. Parte 2

Publicamos recentemente uma tradução do material, que fornecia dicas úteis para programadores de Python. Esse material tem uma sequência que chamamos a sua atenção hoje.



Nomeação de fatia usando a função de fatia


Trabalhar com os muitos valores especificados por índices pode rapidamente se transformar em confusão - tanto em termos de suporte quanto em legibilidade do código. Uma maneira de melhorar a situação é usar constantes para os valores especificados pelos índices. Mas há uma maneira melhor de escrever código de qualidade:

#       ID First Name   Last Name line_record = "2    John Smith" ID = slice(0, 8) FIRST_NAME = slice(9, 21) LAST_NAME = slice(22, 27) name = f"{line_record[FIRST_NAME].strip()} {line_record[LAST_NAME].strip()}" # name == "John Smith" 

Neste exemplo, você pode ver que, dando nomes às fatias usando a função slice e usando esses nomes para obter os fragmentos da sequência, conseguimos nos livrar dos índices complexos. Você pode aprender mais sobre o objeto de slice usando seus .start , .stop e .step .

Solicitando uma senha do usuário durante a execução do programa


Muitas ferramentas ou scripts de linha de comando exigem um nome de usuário e senha para funcionar. Se você precisar escrever um programa assim, poderá achar getpass módulo getpass :

 import getpass user = getpass.getuser() password = getpass.getpass() #   ... 

Este pacote muito simples permite que você solicite a senha de um usuário e obtenha um nome de usuário recuperando o nome com o qual ele está conectado. No entanto, ao trabalhar com senhas, você deve estar ciente de que nem todos os sistemas oferecem suporte à ocultação de senhas. O Python tentará notificá-lo. Se isso acontecer, você verá um aviso correspondente na linha de comando.

Localizando correspondências próximas em strings


Agora vamos falar sobre um recurso um pouco mais misterioso da biblioteca padrão do Python. Suponha que você esteja em uma situação em que precisava, usando um conceito como a distância de Levenshtein , para encontrar palavras na lista que se pareçam com uma determinada linha de entrada. Este problema pode ser resolvido usando o módulo difflib .

 import difflib difflib.get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'], n=2) # returns ['apple', 'ape'] 

O método difflib.get_close_matches as melhores correspondências "boas o suficiente". O primeiro argumento deste método especifica a cadeia de pesquisa, o segundo argumento especifica a lista na qual a pesquisa é realizada. Este método pode receber um argumento opcional n , que especifica o número máximo de correspondências retornadas. Esse método também suporta o cutoff opcional de argumento nomeado (por padrão, é definido como 0.6 ), que permite definir um valor limite para avaliar correspondências.

Trabalhar com endereços IP


Se você precisar escrever programas Python para trabalhar com a rede, isso significa que o módulo ipaddress pode ser muito útil para você. Uma opção para usá-lo é gerar uma lista de endereços IP a partir de um intervalo de endereços especificado no formato CIDR (roteamento entre domínios sem classe, endereçamento sem classe).

 import ipaddress net = ipaddress.ip_network('74.125.227.0/29') #      IPv6 # IPv4Network('74.125.227.0/29') for addr in net:    print(addr) # 74.125.227.0 # 74.125.227.1 # 74.125.227.2 # 74.125.227.3 # ... 

Outro recurso útil deste módulo é verificar o endereço IP por pertencer a uma determinada rede:

 ip = ipaddress.ip_address("74.125.227.3") ip in net # True ip = ipaddress.ip_address("74.125.227.12") ip in net # False 

O módulo ipaddress possui muitos outros recursos interessantes dos quais não estou falando aqui. Leia mais sobre ele aqui . É verdade que, usando este módulo, considere as limitações relacionadas ao seu trabalho conjunto com outros módulos relacionados à programação de rede. Por exemplo, você não pode usar instâncias IPv4Network como cadeias de endereços. Objetos semelhantes para isso devem primeiro ser convertidos em strings usando str .

Depurando um programa na linha de comando


Se você é um daqueles que não deseja usar o IDE e escreve código no Vim ou no Emacs, pode estar em uma situação em que precisaria de um depurador como o do IDE. E você sabe o que? Você já possui um depurador. Para usá-lo, basta executar o programa usando uma estrutura como python3.8 -i . O sinalizador -i permite, após a conclusão do programa, iniciar um shell interativo. Usando-o, você pode examinar variáveis ​​e chamar funções. Esse é um recurso interessante, mas e um depurador real (pdb)? Vamos experimentar o seguinte programa simples, cujo código está no arquivo script.py :

 def func():    return 0 / 0 func() 

Execute-o com o python3.8 -i script.py e obtenha o seguinte:

 #   ... Traceback (most recent call last):  File "script.py", line 4, in <module>    func()  File "script.py", line 2, in func    return 0 / 0 ZeroDivisionError: division by zero >>> import pdb >>> pdb.pm() #      > script.py(2)func() -> return 0 / 0 (Pdb) 

Vemos o local do programa em que ocorreu o acidente. Defina um ponto de interrupção:

 def func():    breakpoint() # import pdb; pdb.set_trace()    return 0 / 0 func() 

Execute o script novamente.

script.py(3)func()
-> return 0 / 0
(Pdb) #
(Pdb) step
ZeroDivisionError: division by zero
> script.py(3)func()
-> return 0 / 0
(Pdb)

Na maioria das situações, o comando print e os resultados do rastreio são suficientes para scripts de depuração, mas, às vezes, para lidar com uma falha complexa, você precisa se aprofundar no programa e entender a essência do que está acontecendo. Nesses casos, os pontos de interrupção são definidos no código e o programa é examinado. Por exemplo, eles examinam os argumentos das funções, avaliam expressões, verificam os valores das variáveis ​​ou, como mostrado acima, apenas executam o código passo a passo. Pdb é um wrapper Python totalmente funcional. Nesse shell, você pode fazer quase qualquer coisa. No decorrer do trabalho, alguns comandos específicos do depurador serão úteis, para os quais pode ser encontrada ajuda aqui .

Declarando vários construtores em uma classe


A sobrecarga de funções é um dos recursos amplamente usados ​​em várias linguagens de programação, mas não no Python. E mesmo que você não possa sobrecarregar uma função regular no Python, podemos usar algo como sobrecarregar construtores usando métodos de classe:

 import datetime class Date:    def __init__(self, year, month, day):        self.year = year        self.month = month        self.day = day    @classmethod    def today(cls):        t = datetime.datetime.now()        return cls(t.year, t.month, t.day) d = Date.today() print(f"{d.day}/{d.month}/{d.year}") # 14/9/2019 

Em uma situação semelhante, em vez de usar métodos de classe, você pode ficar tentado a colocar toda a lógica de construtores alternativos em __init__ e resolver o problema usando *args , **kwargs e muitas if . O resultado pode estar funcionando, mas será difícil ler e manter esse código. Aqui eu recomendaria colocar um mínimo de lógica em __init__ e executar todas as operações em métodos / construtores separados. Com essa abordagem, teremos à disposição um código limpo que será conveniente tanto para o autor desse código quanto para quem o usará.

Armazenando em cache resultados de chamadas de função usando um decorador


Você já escreveu funções que executavam algumas operações longas de leitura / gravação ou cálculos recursivos lentos? Ao mesmo tempo, você achou que o armazenamento em cache dos resultados não prejudicaria essas funções? Você pode armazenar em cache (memorizar) os resultados de uma chamada de função usando o decorador functools módulo functools :

 from functools import lru_cache import requests @lru_cache(maxsize=32) def get_with_cache(url):    try:        r = requests.get(url)        return r.text    except:        return "Not Found" for url in ["https://google.com/",            "https://martinheinz.dev/",            "https://reddit.com/",            "https://google.com/",            "https://dev.to/martinheinz",            "https://google.com/"]:    get_with_cache(url) print(get_with_cache.cache_info()) # CacheInfo(hits=2, misses=4, maxsize=32, currsize=4) 

Neste exemplo, executamos solicitações GET cujos resultados são armazenados em cache (até 32 resultados podem ser armazenados em cache). Aqui você pode ver que obtemos informações sobre o cache da função usando o método cache_info . O decorador também nos fornece o método clear_cache , que é usado para clear_cache cache. Aqui também gostaria de observar que o cache não pode ser usado com funções com efeitos colaterais ou com funções que criam objetos mutáveis ​​a cada chamada.

Localizando itens que são encontrados no objeto iterável com mais frequência


Estar na lista de elementos que são encontrados nela com mais frequência do que outros é uma tarefa muito comum. Você pode resolvê-lo, por exemplo, usando o loop for e um dicionário, que coletará informações sobre o número de elementos idênticos. Mas essa abordagem é uma perda de tempo. O fato é que você pode resolver esses problemas usando a classe Counter no módulo de collections :

 from collections import Counter cheese = ["gouda", "brie", "feta", "cream cheese", "feta", "cheddar",          "parmesan", "parmesan", "cheddar", "mozzarella", "cheddar", "gouda",          "parmesan", "camembert", "emmental", "camembert", "parmesan"] cheese_count = Counter(cheese) print(cheese_count.most_common(3)) # : [('parmesan', 4), ('cheddar', 3), ('gouda', 2)] 

Os mecanismos internos da classe Counter são baseados em um dicionário que armazena a correspondência de elementos e o número de entradas na lista. Portanto, o objeto correspondente pode ser usado como um objeto de dict regular:

 print(cheese_count["mozzarella"]) # : 1 cheese_count["mozzarella"] += 1 print(cheese_count["mozzarella"]) # : 2 

Além disso, ao trabalhar com o Counter , temos à disposição o método update(more_words) , que é usado para adicionar novos elementos ao contador. Outro recurso útil do Counter é que ele permite que você use operações matemáticas (adição e subtração) ao trabalhar com instâncias dessa classe.

Sumário


Eu acho que a maioria das dicas dadas hoje pode muito bem ser usada por quem escreve em Python quase diariamente. Espero que você encontre entre eles algo que seja útil para você.

Caros leitores! Você conhece algum truque interessante de programação em Python? Se sim, compartilhe-os.

Source: https://habr.com/ru/post/pt485646/


All Articles