portaldacalheta.pt
  • Principal
  • Investidores E Financiamento
  • Gerenciamento De Projetos
  • Noticias Do Mundo
  • Processo De Design
Tecnologia

Código Python com erros: Os 10 erros mais comuns cometidos pelos desenvolvedores de Python



Sobre Python

Pitão é uma linguagem de programação interpretada, orientada a objetos e de alto nível com semântica dinâmica. Suas estruturas de dados embutidas de alto nível, combinadas com tipagem dinâmica e vinculação dinâmica, tornam-no muito atraente para Desenvolvimento de Aplicação Rápida , bem como para uso como linguagem de script ou cola para conectar componentes ou serviços existentes. Python oferece suporte a módulos e pacotes, incentivando assim a modularidade do programa e a reutilização de código.

Sobre este artigo

A sintaxe simples e fácil de aprender do Python pode enganar Desenvolvedores Python - especialmente aqueles que são mais novos na língua - perdendo algumas de suas sutilezas e subestimando o poder do linguagem Python diversa .



Com isso em mente, este artigo apresenta uma lista dos '10 principais' de erros um tanto sutis e difíceis de detectar que podem afetar ainda mais desenvolvedores avançados de Python na traseira.



tutorial de aprendizado de máquina para iniciantes

(Observação: este artigo se destina a um público mais avançado do que Erros comuns de programadores Python , que é mais voltado para aqueles que são novos no idioma.)



Erro comum nº 1: uso indevido de expressões como padrões para argumentos de função

Python permite que você especifique que um argumento de função é opcional fornecendo um valor padrão para isso. Embora seja um ótimo recurso da linguagem, pode causar alguma confusão quando o valor padrão é mutável . Por exemplo, considere esta definição de função Python:

>>> def foo(bar=[]): # bar is optional and defaults to [] if not specified ... bar.append('baz') # but this line could be problematic, as we'll see... ... return bar

Um erro comum é pensar que o argumento opcional será definido para a expressão padrão especificada cada vez a função é chamada sem fornecer um valor para o argumento opcional. No código acima, por exemplo, pode-se esperar que a chamada foo() repetidamente (ou seja, sem especificar um bar argumento) sempre retornaria 'baz', uma vez que a suposição seria que cada vez foo() é chamado (sem um argumento bar especificado) bar está definido como [] (ou seja, uma nova lista vazia).



Mas vamos ver o que realmente acontece quando você faz isso:

>>> foo() ['baz'] >>> foo() ['baz', 'baz'] >>> foo() ['baz', 'baz', 'baz']

Hã? Por que ele continuou acrescentando o valor padrão de 'baz' para um existir listar cada vez foo() foi chamado, em vez de criar um Novo lista cada vez?



A resposta de programação Python mais avançada é que o valor padrão para um argumento de função é avaliado apenas uma vez, no momento em que a função é definida. Assim, o bar argumento é inicializado com seu padrão (ou seja, uma lista vazia) somente quando foo() é definido primeiro, mas depois chama foo() (ou seja, sem um argumento bar especificado) continuará a usar a mesma lista para a qual bar foi inicializado originalmente.

Para sua informação, uma solução alternativa comum para isso é a seguinte:



>>> def foo(bar=None): ... if bar is None: # or if not bar: ... bar = [] ... bar.append('baz') ... return bar ... >>> foo() ['baz'] >>> foo() ['baz'] >>> foo() ['baz']

Erro comum nº 2: usar variáveis ​​de classe incorretamente

Considere o seguinte exemplo:

>>> class A(object): ... x = 1 ... >>> class B(A): ... pass ... >>> class C(A): ... pass ... >>> print A.x, B.x, C.x 1 1 1

Faz sentido.



>>> B.x = 2 >>> print A.x, B.x, C.x 1 2 1

Sim, novamente como esperado.

>>> A.x = 3 >>> print A.x, B.x, C.x 3 2 3

O que $% #! & ?? Nós apenas mudamos A.x. Por que C.x mudar também?



Em Python, as variáveis ​​de classe são tratadas internamente como dicionários e seguem o que costuma ser chamado de Pedido de resolução de método (MRO) . Portanto, no código acima, uma vez que o atributo x não for encontrado na classe C, ele será pesquisado em suas classes base (apenas A no exemplo acima, embora Python suporte várias heranças). Em outras palavras, C não tem seu próprio x propriedade, independente de A. Portanto, referências a C.x são, na verdade, referências a A.x. Isso causa um problema no Python, a menos que seja tratado corretamente. Aprender mais sobre atributos de classe em Python .

Erro comum nº 3: Especificar parâmetros incorretamente para um bloco de exceção

Suponha que você tenha o seguinte código:

>>> try: ... l = ['a', 'b'] ... int(l[2]) ... except ValueError, IndexError: # To catch both exceptions, right? ... pass ... Traceback (most recent call last): File '', line 3, in IndexError: list index out of range

O problema aqui é que except declaração faz não pegue uma lista de exceções especificadas dessa maneira. Em vez disso, no Python 2.x, a sintaxe except Exception, e é usado para ligar a exceção ao opcional segundo parâmetro especificado (neste caso e), a fim de torná-lo disponível para inspeção posterior. Como resultado, no código acima, o IndexError exceção é não sendo pego pelo except declaração; em vez disso, a exceção acaba sendo vinculada a um parâmetro denominado IndexError.

o que é adobe xd cc

A maneira correta de capturar várias exceções em um except declaração é especificar o primeiro parâmetro como um tupla contendo todas as exceções a serem capturadas. Além disso, para portabilidade máxima, use o as palavra-chave, uma vez que essa sintaxe é compatível com Python 2 e Python 3:

>>> try: ... l = ['a', 'b'] ... int(l[2]) ... except (ValueError, IndexError) as e: ... pass ... >>>

Erro comum nº 4: entender mal as regras de escopo do Python

A resolução de escopo Python é baseada no que é conhecido como LEGB regra, que é uma abreviação de eu ocal, É fechando, G lobal, B uilt-in. Parece bastante direto, certo? Bem, na verdade, existem algumas sutilezas na maneira como isso funciona em Python, o que nos leva ao problema comum de programação Python mais avançado a seguir. Considere o seguinte:

>>> x = 10 >>> def foo(): ... x += 1 ... print x ... >>> foo() Traceback (most recent call last): File '', line 1, in File '', line 2, in foo UnboundLocalError: local variable 'x' referenced before assignment

Qual é o problema?

O erro acima ocorre porque, quando você faz um tarefa a uma variável em um escopo, essa variável é automaticamente considerada pelo Python como local para esse escopo e sombreia qualquer variável com nome semelhante em qualquer escopo externo.

Muitos ficam, portanto, surpresos ao receber um UnboundLocalError no código que funcionava anteriormente, quando ele é modificado pela adição de uma instrução de atribuição em algum lugar do corpo de uma função. (Você pode ler mais sobre isso Aqui .)

É particularmente comum que isso atrapalhe os desenvolvedores ao usar listas . Considere o seguinte exemplo:

>>> lst = [1, 2, 3] >>> def foo1(): ... lst.append(5) # This works ok... ... >>> foo1() >>> lst [1, 2, 3, 5] >>> lst = [1, 2, 3] >>> def foo2(): ... lst += [5] # ... but this bombs! ... >>> foo2() Traceback (most recent call last): File '', line 1, in File '', line 2, in foo UnboundLocalError: local variable 'lst' referenced before assignment

Hã? Por que foo2 bombar enquanto foo1 correu bem?

A resposta é a mesma do problema do exemplo anterior, mas é reconhecidamente mais sutil. foo1 não está fazendo um tarefa para lst, enquanto foo2 é. Lembrando que lst += [5] é apenas uma abreviação para lst = lst + [5], vemos que estamos tentando atribuir um valor para lst (portanto, presume-se que o Python esteja no escopo local). No entanto, o valor que estamos procurando atribuir a lst é baseado em lst em si (novamente, agora presumivelmente no âmbito local), que ainda não foi definido. Estrondo.

Erro comum nº 5: modificar uma lista ao iterar sobre ela

O problema com o código a seguir deve ser bastante óbvio:

>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> for i in range(len(numbers)): ... if odd(numbers[i]): ... del numbers[i] # BAD: Deleting item from a list while iterating over it ... Traceback (most recent call last): File '', line 2, in IndexError: list index out of range

Excluir um item de uma lista ou array durante a iteração é um problema Python bem conhecido por qualquer desenvolvedor de software experiente. Mas, embora o exemplo acima possa ser bastante óbvio, mesmo os desenvolvedores avançados podem ser acidentalmente mordidos por isso em um código que é muito mais complexo.

Felizmente, o Python incorpora vários paradigmas de programação elegantes que, quando usados ​​corretamente, podem resultar em um código significativamente simplificado e otimizado. Um benefício colateral disso é que o código mais simples tem menos probabilidade de ser mordido pelo bug de exclusão acidental de um item da lista durante a iteração. Um desses paradigmas é o de listar compreensões . Além disso, as compreensões de lista são particularmente úteis para evitar esse problema específico, conforme mostrado por esta implementação alternativa do código acima, que funciona perfeitamente:

>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all >>> numbers [0, 2, 4, 6, 8]

Erro comum nº 6: confundir como o Python vincula variáveis ​​em encerramentos

Considerando o seguinte exemplo:

>>> def create_multipliers(): ... return [lambda x : i * x for i in range(5)] >>> for multiplier in create_multipliers(): ... print multiplier(2) ...

Você pode esperar a seguinte saída:

0 2 4 6 8

Mas você realmente obtém:

8 8 8 8 8

Surpresa!

movimento nos princípios do design

Isso acontece devido ao Python ligação tardia comportamento que diz que os valores das variáveis ​​usadas nos fechamentos são consultados no momento em que a função interna é chamada. Portanto, no código acima, sempre que qualquer uma das funções retornadas é chamada, o valor de i é procurado no escopo circundante no momento em que é chamado (e até lá, o loop foi concluído, então i já recebeu seu valor final de 4).

A solução para esse problema comum do Python é meio hack:

>>> def create_multipliers(): ... return [lambda x, i=i : i * x for i in range(5)] ... >>> for multiplier in create_multipliers(): ... print multiplier(2) ... 0 2 4 6 8

Voilà! Estamos aproveitando os argumentos padrão aqui para gerar funções anônimas a fim de alcançar o comportamento desejado. Alguns diriam que é elegante. Alguns diriam que é sutil. Alguns odeiam. Mas se você é um desenvolvedor Python, é importante entender em qualquer caso.

Erro comum nº 7: Criação de dependências de módulo circular

Digamos que você tenha dois arquivos, a.py e b.py, cada um importando o outro, como segue:

Em a.py:

import b def f(): return b.x print f()

E em b.py:

import a x = 1 def g(): print a.f()

Primeiro, vamos tentar importar a.py:

>>> import a 1

Funcionou muito bem. Talvez isso o surpreenda. Afinal, temos uma importação circular aqui que presumivelmente deve ser um problema, não é?

A resposta é que o simples presença de uma importação circular não é, por si só, um problema em Python. Se um módulo já foi importado, o Python é inteligente o suficiente para não tentar importá-lo novamente. No entanto, dependendo do ponto em que cada módulo está tentando acessar funções ou variáveis ​​definidas no outro, você pode de fato ter problemas.

Portanto, voltando ao nosso exemplo, quando importamos a.py, não houve problemas para importar b.py, pois b.py não requer nada de a.py a ser definida no momento em que é importado . A única referência em b.py para a é a chamada para a.f(). Mas essa chamada está em g() e nada em a.py ou b.py invoca g(). Então a vida é boa.

Mas o que acontece se tentarmos importar b.py (sem ter importado anteriormente a.py, isto é):

>>> import b Traceback (most recent call last): File '', line 1, in File 'b.py', line 1, in import a File 'a.py', line 6, in print f() File 'a.py', line 4, in f return b.x AttributeError: 'module' object has no attribute 'x'

Opa. Isso não é bom! O problema aqui é que, no processo de importação b.py, ele tenta importar a.py, que por sua vez chama f(), que tenta acessar b.x. Mas b.x ainda não foi definido. Portanto, o AttributeError exceção.

Pelo menos uma solução para isso é bastante trivial. Basta modificar b.py para importar a.py dentro g():

x = 1 def g(): import a # This will be evaluated only when g() is called print a.f()

Não, quando importamos, está tudo bem:

>>> import b >>> b.g() 1 # Printed a first time since module 'a' calls 'print f()' at the end 1 # Printed a second time, this one is our call to 'g'

Erro comum nº 8: conflito de nomes com módulos da biblioteca padrão Python

Uma das belezas do Python é a riqueza de módulos de biblioteca que vem com 'fora da caixa'. Mas, como resultado, se você não o estiver evitando conscientemente, não é tão difícil encontrar um conflito de nomes entre o nome de um de seus módulos e um módulo com o mesmo nome na biblioteca padrão que vem com o Python (por exemplo , você pode ter um módulo denominado email.py em seu código, o que estaria em conflito com o módulo de biblioteca padrão de mesmo nome).

Isso pode levar a problemas complicados, como importar outra biblioteca que, por sua vez, tenta importar a versão da biblioteca padrão do Python de um módulo, mas, uma vez que você tem um módulo com o mesmo nome, o outro pacote importa por engano sua versão em vez de dentro a biblioteca padrão do Python. É aqui que ocorrem os erros graves do Python.

Portanto, deve-se tomar cuidado para evitar o uso dos mesmos nomes dos módulos da biblioteca padrão do Python. É muito mais fácil para você alterar o nome de um módulo dentro do seu pacote do que arquivar um Proposta de aprimoramento Python (PEP) para solicitar uma mudança de nome no upstream e tentar aprová-la.

Erro comum nº 9: não abordar as diferenças entre Python 2 e Python 3

Considere o seguinte arquivo foo.py:

import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def bad(): e = None try: bar(int(sys.argv[1])) except KeyError as e: print('key error') except ValueError as e: print('value error') print(e) bad()

No Python 2, isso funciona bem:

$ python foo.py 1 key error 1 $ python foo.py 2 value error 2

Mas agora vamos dar uma olhada no Python 3:

qual é o trabalho de um CFO
$ python3 foo.py 1 key error Traceback (most recent call last): File 'foo.py', line 19, in bad() File 'foo.py', line 17, in bad print(e) UnboundLocalError: local variable 'e' referenced before assignment

O que acabou de acontecer aqui? O “problema” é que, no Python 3, o objeto de exceção não está acessível além do escopo do except quadra. (A razão para isso é que, caso contrário, ele manteria um ciclo de referência com o quadro de pilha na memória até que o coletor de lixo execute e limpe as referências da memória. Mais detalhes técnicos sobre isso estão disponíveis Aqui )

Uma maneira de evitar esse problema é manter uma referência ao objeto de exceção lado de fora o escopo do except bloquear para que permaneça acessível. Esta é uma versão do exemplo anterior que usa essa técnica, gerando um código que é compatível com Python 2 e Python 3:

import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def good(): exception = None try: bar(int(sys.argv[1])) except KeyError as e: exception = e print('key error') except ValueError as e: exception = e print('value error') print(exception) good()

Executando isso no Py3k:

$ python3 foo.py 1 key error 1 $ python3 foo.py 2 value error 2

Yippee!

(Aliás, nosso Guia de contratação de Python discute uma série de outras diferenças importantes a serem observadas ao migrar o código do Python 2 para o Python 3.)

Erro comum nº 10: Uso indevido de __del__ método

Digamos que você tenha isso em um arquivo chamado mod.py:

import foo class Bar(object): ... def __del__(self): foo.cleanup(self.myhandle)

E você então tentou fazer isso de another_mod.py:

import mod mybar = mod.Bar()

Você ficaria com um AttributeError feio | exceção.

Por quê? Porque, conforme relatado Aqui , quando o interpretador é desligado, as variáveis ​​globais do módulo são definidas como None. Como resultado, no exemplo acima, no ponto que __del__ é invocado, o nome foo já foi definido como None.

Uma solução para este problema de programação Python um pouco mais avançado seria usar atexit.register() em vez de. Dessa forma, quando a execução do programa terminar (ou seja, ao sair normalmente), seus manipuladores registrados serão iniciados antes o intérprete é desligado.

Com esse entendimento, uma correção para o acima mod.py o código pode ser mais ou menos assim:

diferença entre llc c corp e s corp
import foo import atexit def cleanup(handle): foo.cleanup(handle) class Bar(object): def __init__(self): ... atexit.register(cleanup, self.myhandle)

Essa implementação fornece uma maneira limpa e confiável de chamar qualquer funcionalidade de limpeza necessária após o encerramento normal do programa. Obviamente, depende de foo.cleanup para decidir o que fazer com o objeto vinculado ao nome self.myhandle, mas você entendeu.

Embrulhar

Python é uma linguagem poderosa e flexível com muitos mecanismos e paradigmas que podem melhorar muito a produtividade. No entanto, como acontece com qualquer ferramenta de software ou linguagem, ter uma compreensão limitada ou apreciação de seus recursos pode às vezes ser mais um impedimento do que um benefício, deixando alguém no estado proverbial de “saber o suficiente para ser perigoso”.

Familiarizar-se com as principais nuances do Python, como (mas não se limitando a) os problemas de programação moderadamente avançados levantados neste artigo, ajudará a otimizar o uso da linguagem, evitando alguns de seus erros mais comuns.

Você também pode querer verificar nosso Guia do Insider para Entrevistas em Python para sugestões sobre perguntas de entrevista que podem ajudar a identificar especialistas em Python.

Esperamos que você tenha achado as dicas neste artigo úteis e agradecemos seus comentários.

Cada produto tem uma tese

Processo E Ferramentas

Cada produto tem uma tese
A História do Trabalho Remoto, 1560-Presente (com Infográfico) (Atualizado)

A História do Trabalho Remoto, 1560-Presente (com Infográfico) (Atualizado)

Ascensão Do Remoto

Publicações Populares
Violência explode em protesto contra o despejo do campo de Berlim
Violência explode em protesto contra o despejo do campo de Berlim
Introdução ao Docker: simplificando o DevOps
Introdução ao Docker: simplificando o DevOps
Ideia brilhante de Donald Trump: uma parede solar na fronteira EUA-México
Ideia brilhante de Donald Trump: uma parede solar na fronteira EUA-México
Uma visão geral completa das melhores ferramentas de visualização de dados
Uma visão geral completa das melhores ferramentas de visualização de dados
O valor do design thinking nos negócios
O valor do design thinking nos negócios
 
Introdução aos microsserviços: um tutorial do Dropwizard
Introdução aos microsserviços: um tutorial do Dropwizard
Com 21 anos e raízes de Kerala, é o mais jovem na lista de MBE do Queen
Com 21 anos e raízes de Kerala, é o mais jovem na lista de MBE do Queen
Um bebê pode ouvir sons no útero?
Um bebê pode ouvir sons no útero?
Os desafios da aprendizagem remota para crianças pequenas
Os desafios da aprendizagem remota para crianças pequenas
ASSISTIR: A sessão de fotos do casamento de noivas captura o momento em que a explosão rasgou a cidade de Beirute
ASSISTIR: A sessão de fotos do casamento de noivas captura o momento em que a explosão rasgou a cidade de Beirute
Publicações Populares
  • Qual das opções a seguir é importante ter em mente ao criar seu design para celular?
  • classificação llc c ou s
  • origens da crise da dívida grega
  • download gratuito de software de hacker de cartão de crédito
  • como obter a certificação aws
  • o que é um fundo de quantia
Categorias
  • Investidores E Financiamento
  • Gerenciamento De Projetos
  • Noticias Do Mundo
  • Processo De Design
  • © 2022 | Todos Os Direitos Reservados

    portaldacalheta.pt