Indice
20 erros comuns do Python que você deve evitar
Sendo uma linguagem de programação extremamente simplista, minimalista e fácil de entender, o Python é hoje mundialmente aceito e usado universalmente. O Python permite que você atenda rapidamente e incorpore sistemas com mais eficiência. Apesar de ser uma linguagem simples, há uma série de erros que os programadores tendem a cometer enquanto trabalham nela. Vamos ver o que eles são.
Python é uma linguagem de programação geral e multifuncional, de alto nível, interpretada e orientada a objetos, universalmente usada. Hoje, vamos falar sobre os erros comuns dos programadores Python.
Python é amigável para iniciantes e é extremamente simplista, minimalista e fácil de entender. Sua natureza de pseudocódigo é um de seus poderes mais proeminentes que permite meditar na solução do problema e não apenas na linguagem.
Além disso, o Python permite que você atenda rapidamente e incorpore sistemas com mais eficiência.
Embora o Python seja reconhecido como uma linguagem de alto nível novata e favorável e notavelmente superior, triunfante e amplamente adotada como linguagem de programação de uso geral,
Existem muitos erros comuns dos programadores Python. Vamos descobrir os erros mais comuns do desenvolvimento Python.
Erros comuns do desenvolvimento Python
Manipulação de erros
As falhas em Python têm um tipo muito distinto, chamado de traceback. Você precisa ter uma ideia de todos os erros do Python para poder se tornar ótimo em python.
Quando você pula dois pontos no final de uma linha ou acidentalmente adiciona espaço extra ao recuar sob uma instrução if, ou se lembra incorretamente de um parêntese, você enfrentará um erro de sintaxe.
Isso significa que o Python não conseguiu compreender seu programa.
Recuo incorreto
Para mostrar um bloco de código em Python, cada linha do bloco deve ser sinalizada pelo volume correspondente.
Ao contrário de outras linguagens, o recuo do Python indica muito mais do que simplesmente fazer o código parecer limpo. É necessário para simbolizar a qual bloco de código uma instrução pertence. Várias características dependem do recuo.
Poucos erros de recuo são mais difíceis de detectar em Python do que outros. Por exemplo, emaranhar espaços e tabulações pode ser um desafio para localizar em um código.
Nesse caso, o que for observado no editor pode não ser visualizado pelo Python quando as tabulações estiverem sendo computadas como representação de espaços.
O notebook Jupyter suplanta as guias com espaços automaticamente, mas gera um erro no máximo de casos. Para ignorar isso para o bloco inteiro, todos os espaços ou todas as guias devem ser aplicadas.
Uso Indevido de The_init_Method
O init é um programa conservado em classes python que são empregadas como construtores e assim denominadas na terminologia orientada a objetos. E chega quando o Python distribui memória para um novo objeto de classe.
Esse processo é invocado quando um objeto é produzido a partir de uma classe e permite que a classe inicialize os atributos da classe. É um dos erros fatais do Python.
O objetivo é ancorar os valores dos membros da instância para o objeto de classe. A tentativa de retornar explicitamente um valor do método init significa que o usuário deseja divergir de sua missão original.
Variáveis de classe
Em Python, as variáveis de classe são gerenciadas de forma privada como dicionários e obedecem a Ordem de Resolução de Método ou MRO.
Significa o caminho de pesquisa de classe empregado pelo Python para procurar a técnica correta a ser utilizada em classes com multi-herança. Isso leva a um problema do Python, a menos que funcione corretamente.
Nome do módulo da biblioteca padrão do Python
Python é próspero com módulos de biblioteca prontos para uso. Um erro comum é o uso de nomes idênticos para módulos na biblioteca padrão do Python.
Isso direciona para carregar diferentes bibliotecas que tentarão importar o módulo na biblioteca padrão do Python e, devido ao módulo com o nome igual, o outro pacote importará o módulo definido, em vez do módulo da biblioteca padrão do Python.
Regra LEGB
A resolução do escopo do Python é baseada na regra LEGB ou na regra Local, Enclosing, Global, Built-in. Python emprega uma estratégia única para variáveis de escopo do que outras linguagens de programação.
Se um usuário cria uma atribuição para uma variável em um intervalo, essa variável é automaticamente reconhecida pelo Python como local para esse escopo e oculta qualquer variável chamada semelhante em um escopo externo.
Esses erros do Python são especialmente comuns para desenvolvedores ao usar listas.
Uso indevido de expressões
Python permite determinar que um argumento de função é arbitrário, fornecendo um valor padrão para ele. Embora esta seja uma excelente marca registrada da linguagem, ela pode causar caos quando o valor padrão é mutável. Por exemplo, considere esta definição de função Python:
>>> def foo(bar=[]): # bar is voluntary and defaults to [] if not defined
... bar.append("baz") # but this line can be problematic
... return bar
Uma confusão frequente é assumir que o argumento opcional será ancorado à expressão padrão designada a cada ponto em que a função for declarada sem fornecer um valor para o argumento opcional.
Especificando parâmetros errados para exceção
Vamos supor que você tenha o código fornecido abaixo:
>>> try:
... l = ["a", "b"]
... int(l[2])
... except ValueError, IndexError: # To catch both exceptions, right?
... pass
...
Traceback (latest dialled last):
File "<stdin>", line 3, in <module>
IndexError: list index out of range
O problema aqui é que a instrução except não aceita uma lista de exceções descritas dessa maneira.
Em vez disso, no Python 2.x , a sintaxe except for Exception é utilizada para encapsular a exceção no segundo parâmetro opcional definido (neste evento e), para torná-lo acessível para investigação adicional.
Portanto, no código anterior, a exceção IndexError não está sendo selecionada pela instrução except; em vez disso, a exceção acaba sendo vinculada a IndexError.
A maneira convencional de capturar exceções recorrentes em uma instrução except é estipular o primeiro parâmetro como uma tupla contendo todas as exceções a serem conectadas.
Além disso, para portabilidade suprema, use the como palavra-chave, pois essa sintaxe é sustentada por Python 2 e Python 3 :
>>> try:
... l = ["a", "b"]
... int(l[2])
... except (ValueError, IndexError) as e:
... pass
...
>>>
Incompreensão do escopo do Python
A análise de escopo do Python é baseada no que é conhecido como regra LEGB ou regra Local, Enclosing, Global, Built-in.
No entanto, não é tão simples quanto parece. É um dos erros mais comuns em Python. Mas, você pode evitar esses erros, então o Python é uma ótima opção para startups .
Existem algumas implicações para o processo que funciona em Python, o que nos leva à consulta de programação Python mais avançada abaixo. Analise isso:
>>> x = 10
>>> def foo():
... x += 1
... print x
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment
Qual é o problema?
O erro anterior acontece quando você executa uma atribuição a uma variável em um escopo, essa variável é, por padrão, reconhecida pelo Python como local para esse escopo e ignora qualquer variável denominada idêntica em qualquer escopo externo.
Muitos são assim capturados para obter um UnboundLocalError no código de trabalho anterior quando ele é alterado pela sobreposição de uma instrução de atribuição ao redor do corpo de uma função.
É especialmente comum confundir os desenvolvedores ao utilizar listas. Considere o exemplo fornecido abaixo:
>>> lst = [1, 2, 3]
>>> def foo1():
... lst.append(5) # This goes well...
...
>>> foo1()
>>> lst
[1, 2, 3, 5]
>>> lst = [1, 2, 3]
>>> def foo2():
... lst += [5] # ...Not this one!
...
>>> foo2()
Traceback (latest call list):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'lst' referenced assignment
Por que foo2 falhou enquanto foo1 funcionou bem?
A resposta é a mesma da consulta de modelo anterior, mas é reconhecidamente mais ilusória. foo1 não está executando uma atribuição para lst, enquanto foo2 está memorizando issolst += [5]é realmente apenas uma forma curta paralst = lst + [5]
Modificando a lista enquanto a iteração está ativada
O problema com o código abaixo parece ó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: Removing item from a list while repeating over it
...
Traceback (latest call last):
File "<stdin>", line 2, in <module>
IndexError: list index out of range
Remover um item de uma tabela ou array enquanto o repete é uma complexidade do Python que é bastante familiar para os desenvolvedores python experientes .
Mas, embora a ilustração acima possa parecer óbvia, mesmo desenvolvedores superiores podem ser acidentalmente atingidos por isso no código, pois é extremamente complicado.
Felizmente, o Python inclui alguns padrões de programação sofisticados que, quando usados corretamente, podem produzir um código notavelmente claro e com contornos.
Uma vantagem adicional aqui é que quanto mais simplista for o código, menos propenso a ser atacado pelo bug de exclusão inesperada de um item da lista enquanto enfatiza sobre ele.
Ligação de Variáveis Python
Considere este exemplo:
>>> def create_multipliers():
... return [lambda x : i * x for i in range(5)]
>>> for multiplier in create_multipliers():
... print multiplier(2)
...
Você pode antecipar a saída subsequente:
0
2
4
6
8
No entanto, você realmente recebe:
8
8
8
8
8
Estrondo!
Isso ocorre devido ao comportamento late-binding do Python que afirma que os valores das variáveis empregadas nos closures são vistos no momento em que a função interna é declarada. É um dos erros mais comuns em Python.
Assim, no código anterior, sempre que qualquer uma das funções retornadas é invocada, o valor dela é pesquisado no escopo vizinho no ponto em que é convocado (e quando o loop termina, ele já foi consignado ao seu valor de 4).
A solução para este problema do Python é uma espécie de truque:
>>> 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
E aí está! Estamos testando o poder dos argumentos padrão aqui para criar funções pseudônimas para realizar o comportamento imaginado.
Pode ser sofisticado para alguns, enquanto para outros é sutil. Alguns também podem evitá-lo. Mas para um desenvolvedor Python, é essencial entender isso em qualquer caso.
Criando dependências modulares circulares
Vamos supor que você tenha dois arquivos, a.py e b.py, que importam um ao outro, da seguinte forma:
In a.py:
import b
def f():
return b.x
print f()
In b.py:
import a
x = 1
def g():
print a.f()
Primeiro, vamos tentar importar a.py:
>>> import a
1
Operado com precisão! Possivelmente isso o sobrecarrega. Afinal, temos uma importação circular aqui que provavelmente deve ser um problema.
A presença de uma importação circular é um dilema em si no Python. Se um módulo já foi importado, o Python é inteligente o suficiente para não reimportá-lo.
No entanto, dependendo da posição em que cada módulo se aventura a alcançar funções ou variáveis delineadas no outro, encontrar problemas parece óbvio.
Então, voltando ao nosso modelo, onde importamos o a.py e não tivemos dificuldade em importar o b.py, pois o b.py não precisa que nada do a.py seja determinado no momento da importação.
A única citação em b.py para a é a chamada para af(). Mas essa chamada está em g() e nada em a.py ou b.py invoca g().
No entanto, o que pode acontecer se tentarmos importar b.py (sem ter importado anteriormente a.py, ou seja):
>>> import b
Traceback (latest call last):
File "<stdin>", line 1, in <module>
File "b.py", line 1, in <module>
import a
File "a.py", line 6, in <module>
print f()
File "a.py", line 4, in f
return b.x
AttributeError: 'module' object has no attribute 'x'
Nós vamos! Há um problema! O método de importar b.py onde se aventura a importar a.py, que em retorno chama f() e tenta alcançar bx é de fato um problema complicado. Mas bx ainda não foi definido. Portanto, a exceção AttributeError.
Mas, pelo menos uma solução para isso é bem menor. Simplesmente altere b.py para importar a.py em g():
x = 1
def g():
import a # This will be assessed only when g() is called
print a.f()
No, when we import it, everything seems perfect:
>>> 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'
Falhando na diferença entre Python 2 e Python 3
Considere o arquivo abaixo 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()
On Python 2, this works well:
$ python foo.py 1
key error
1
$ python foo.py 2
value error
2
Agora vamos transformá-lo em Python 3:
$ python3 foo.py 1
key error
Traceback (latest call last):
File "foo.py", line 19, in <module>
bad()
File "foo.py", line 17, in bad
print(e)
UnboundLocalError: local variable 'e' referenced before assignment
O que acabou de acontecer? O “problema” é que, no Python 3, o objeto de exceção não está disponível fora do escopo do bloco except.
A racionalização para isso é manter um ciclo de referência com o quadro de pilha na memória até que o coletor de lixo opere e esclareça as referências da memória.
Esse problema pode ser contornado mantendo uma referência ao objeto de exceção além do escopo do bloco except para que ele permaneça disponível.
Aqui está uma versão do exemplo anterior que emprega esse procedimento, com código que é favorável ao Python 2 e ao 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()
Running this on Py3k:
$ python3 foo.py 1
key error
1
$ python3 foo.py 2
value error
2
Uso Indevido de The_del_Method
Vamos supor que você tenha isso em um arquivo chamado mod.py:
import foo
class Bar(object):
...
def __del__(self):
foo.cleanup(self.myhandle)
E você tentou fazer isso de another_mod.py:
import mod
mybar = mod.Bar()
Antecipar uma exceção AttributeError inválida.
Isso ocorre porque as variáveis globais do módulo são todas ancoradas em ‘None’ quando o interpretador é encerrado. Como consequência, na instância anterior, no momento em que __del__ é chamado, o nome foo já foi definido como Nenhum.
Uma solução para esse dilema de programação Python de nível relativamente alto seria praticar atexit.register() . Dessa forma, quando um programa termina de ser executado (ao sair normalmente), os manipuladores registrados são impulsionados antes que o interpretador seja selado.
Com essa lógica, uma solução para o código mod.py mencionado acima pode se parecer com isso:
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 um método limpo e seguro de convocar qualquer funcionalidade de limpeza necessária após o encerramento regular do programa.
Certamente, cabe a foo.cleanup julgar o que fazer com o objeto aderido ao nome self.myhandle, mas agora você já sabe.
Identidade equivocada como igualdade
Um erro muito comum que os programadores Python costumam cometer é substituir <is> por <equality> ao relacionar inteiros. Como o Python se aplica a inteiros de cache, eles podem não ser informados dessa viagem.
Para entender melhor esse conceito, vamos considerar os dois exemplos abaixo.
Exemplo 1
Na primeira ilustração, empregamos duas variáveis classificadas como <sum> e <add>. E cada um deles deposita a soma de dois inteiros.
Em seguida, estamos igualando as duas variáveis com operador de igualdade (==). Ele responderá verdadeiro, pois ambas as variáveis mantêm o mesmo valor.
Estamos experimentando com eles utilizando o operador de identidade (“é”), mas isso também retorna true. Isso ocorre porque o Python atribuiu endereços idênticos a ambos, que podem ser autenticados a partir de seus valores de id publicados na borda.
Mas, um programador que pode não saber como as duas operações separadas (“==” e “is”) podem renderizar o mesmo resultado. E, portanto, comete o erro sem conhecimento.
Python 2.7.10 (default, Jul 14 2015, 19:46:27)
[GCC 4.8.2] on linux
sum = 10 + 15
=> None
add = 5 + 20
=> None
sum == add
=> True
sum
=> 25
add
=> 25
sum is add
=> True
id(sum)
=> 25625528
id(add)
=> 25625528
No entanto, vai custar-lhe no exemplo a seguir.
Exemplo-2
Nesse caso, os inteiros longos foram levados em consideração para uso. O truque aqui é que o Python oculta apenas números inteiros entre -5 e 256. Enquanto os números grandes pegam suas caixas individuais para dormir.
Portanto, ao coordenar números inteiros grandes com o operador de identidade (“é”) não retornará o resultado correspondente como no exemplo anterior.
300 + 200 is 500
=> False
300 + 200 == 500
=> True
É sempre aconselhável que os programadores prestem atenção ao conceito antes de usar cegamente qualquer construção.
Uso irracional de antipadrões
Aqui está uma lista de alguns antipadrões que um programador Python pode usar.
Uso da função getter e setter do estilo Java
Em Java, há um uso massivo da função getter/setter para acessar os membros de uma classe. Mas, tal cenário é considerado como um dos erros mais comuns dos programadores Python.
Um exemplo de anti-padrão em Java
class Employee(object):
def __init__(self, name, exp):
self._name = name
self._exp = exp
# Java-style getter/setter
def getName(self):
return self._name
def setName(self, name):
self._name = name
def getExp(self):
return self._exp
def setExp(self, exp):
self._exp = exp
emp = Employee('techbeamers', 10)
print("Employee-1: ", emp.getName(), emp.getExp())
emp.setName('Python Programmer')
emp.setExp(20)
print("Employee-2: ", emp.getName(), emp.getExp())
Como usar isso em Python?
class Employee(object):
def __init__(self, name, exp):
self.name = name
self.exp = exp
emp = Employee('techbeamers', 10)
print("Default: ", emp.name, emp.exp)
emp.name = 'Python Programmer'
emp.exp = 20
print("Updated: ", emp.name, emp.exp)
Usando variável mutável como valor padrão
1
2
3
Vamos pegar uma lista, adicionar 9.
>>> foo()
[9]
>>> foo(numbers=[1,2])
[1, 2, 9]
>>> foo(numbers=[1,2,3])
[1, 2, 3, 9]
1
2
3
4
5
6
E isso acontece ao ligar para foo sem números.
>>> foo() # first time, like before
[9]
>>> foo() # second time
[9, 9]
>>> foo() # third time...
[9, 9, 9]
>>> foo() # Whoa!!
[9, 9, 9, 9]
1
2
3
4
5
6
7
8
Em Python, valores ou funções padrão são instanciados não quando uma função específica é chamada, mas quando ela é determinada.
Solução
def foo(numbers=None):
if numbers are None:
numbers = []
numbers.append(9)
return numbers
1
2
3
4
5
Poucos outros valores padrão parecem funcionar como presumido.
def foo(count=0):
count += 1
return count
1
2
3
4
>>> foo()
1
>>> foo()
1
>>> foo(2)
3
>>> foo(3)
4
>>> foo()
1
1
2
3
4
5
6
7
8
9
10
A lógica para isso não está na atribuição de valor padrão, mas sim no valor. Um inteiro é uma classe imutável. Fazendo count += 1 o valor real de count não está convertendo.
Tente nomear uma função como o valor padrão:
def get_now(now=time.time()):
return now
1
2
Como se vê, enquanto o valor de time.time() é perpétuo, ele retorna o mesmo tempo.
>>> get_now()
1373121487.91
>>> get_now()
1373121487.91
>>> get_now()
1373121487.91
1
2
3
4
5
6
Escrevendo muitos comentários e Docstrings
Como desenvolvedor de aplicativos da Web , se você não conseguir facilitar o código, não dificulte também para outras pessoas. Desenvolva o hábito de escrever comentários e docstrings em seu código. Vai lhe ajudar bastante.
def create_user(name, height=None, weight=None):
'''Create a user entry in database. Returns database object created for user.'''
# Logic to create entry into db and return db object
Criando contagem por um erro em loops
Tenha sempre em mente que um loop raramente conta o número final que você define em um intervalo. Então, se você estipular o intervalo (1, 11), você realmente obtém saída para valores entre 1 e 10.
>>> a = list(range(1, 11))
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[0]
1
>>> a[0:5]
[1, 2, 3, 4, 5]
1
2
3
4
5
6
71
2
36
7
Capitalização errada
Se você não conseguir acessar um valor que antecipou, precisará revisar a capitalização. Python diferencia maiúsculas de minúsculas, portanto MyVar é separado de myvar e MYVAR.
>>> MyVar = 1
>>> MYVAR
Traceback (latest call last):
File "< stdin >", line 1, in < module >
NameError: name 'MYVAR' is not defined
1
2
3
4
5
Utilizando variáveis de classe de forma imprecisa
>> class A(object):
... x = 1
...
>>> class B(A):
... pass
...
>>> class C(A):
... pass
...
>>> print A.x, B.x, C.x
1 1 1
1
2
3
4
5
6
7
8
9
10
11
O exemplo abaixo pode fazer sentido.
>> B.x = 2
>>> print A.x, B.x, C.x
1 2 1
1
2
3
And again.
>>> A.x = 3
>>> print A.x, B.x, C.x
3 2 3
1
2
3
O que fez o Cx mudar se apenas modificamos o Axe? Isso ocorre porque as variáveis de classe em Python têm tratamento interno como dicionários e obedecem à Ordem de Resolução de Métodos (MRO).
É por isso que você verá o trait x apenas em suas classes base (apenas A na instância anterior, embora o Python encoraje heranças múltiplas), pois não há disponibilidade na classe C.
Portanto, C não mantém sua propriedade x individual, separada de A. Da mesma forma, as fontes para Cx são de fato referências a Ax. Isso cria um problema em Python, a menos que você o gerencie corretamente.
Conclusão
Python é uma linguagem fácil, eficaz e adaptável com muitos mecanismos e modelos que podem aumentar consideravelmente a produtividade.
No entanto, existem vários elementos no Python que podem dar errado, principalmente para os novos participantes do Python. Mas, tomando cuidado e mantendo os pontos importantes em mente, esses erros podem ser contornados com bastante facilidade.
Os melhores aplicativos e exemplos de Python fizeram isso e é por isso que são tão bem-sucedidos a longo prazo.
Esperamos que todos tenham se divertido muito lendo este artigo e que seja uma boa ajuda para qualquer desenvolvedor Python em um futuro próximo. Obrigada.!
Gostou? Veja mais sobre Python
As 10 melhores bibliotecas de aprendizado de máquina para PYTHON
Principais plataformas RPA para desenvolvedores Python em 2022
2 FERRAMENTAS -FTP COM PYTHON BAIXANDO ARQUIVOS EM UM SERVIDOR FTP
Créditos: