Python: Tenha cuidado nesses lugares
python é uma linguagem muito interessante. Ela oferece uma série de bibliotecas padrão muito convenientes e muitos comandos embutidos para que possamos executar tarefas com facilidade. Mas quando há muita coisa boa, há o medo de escolha, de modo que não podemos usar muito bem essa biblioteca padrão e suas instituições básicas.
Esta é uma questão que está sendo colocada constantemente no StackOverflow. Como é a experiência de falhar quando seu código perfeito está sendo executado em um computador de outra pessoa, você precisa verificar se sua versão do Python é consistente. Certifique-se de que o código está sendo executado na versão do Python que você conhece.
$ python --version
Python 2.7.9
Gerenciamento de versões python
pyenv é uma ótima ferramenta de gerenciamento de versões em Python. Infelizmente, ela só funciona em*Em sistemas nix. No Mac OS, você pode simplesmente instalar o pyenv com o brew install. No Linux, há um instalador automático.
Muitas pessoas dizem que eu resolvo todos os problemas com uma única linha de código, mesmo que seu código seja menos eficiente do que o normal, e que seja mais difícil de ler, ou até que seja confuso.
l = [m for a, b in zip(this, that) if b.method(a) != b for m in b if not m.method(a, b) and reduce(lambda x, y: a + y.method(), (m, a, b))]
Para ser honesto, o código acima foi escrito por mim mesmo para explicar isso. Mas eu realmente vi muitas pessoas fazerem isso. Se você simplesmente adicionar algo a uma lista ou a um conjunto para mostrar como resolver problemas complexos, então você pode não ser recompensado.
Controlar uma linha de código não é uma grande conquista, embora às vezes pareça especialmente inteligente. Um bom código é simples, mas com mais foco em eficiência e facilidade de leitura.
Este é um problema muito mais delicado, e às vezes pode ser surpreendente.
>>> { n for n in range(10) if n % 2 == 0 }
{0, 8, 2, 4, 6}
>>> type({ n for n in range(10) if n % 2 == 0 })
O exemplo acima mostra isso. Set é um pouco como list em um recipiente. A diferença entre eles é que o conjunto não tem valores repetidos e é desordenado. As pessoas geralmente consideram {} como um conjunto vazio, mas não é, é um ditado vazio.
>>> {}
{}
>>> type({})
Então, se queremos inicializar um conjunto vazio, nós usamos o conjunto ()
>>> set()
set()
>>> type(set())
Observe que um conjunto vazio pode ser representado como um set (), mas um conjunto que contém elementos deve ser definido como um set ().[1, 2])
GIL (global interpreter lock) significa que apenas um thread pode ser executado em um programa Python a qualquer momento. Isso significa que quando não podemos criar um thread e esperar que ele funcione em paralelo. O que o interpreter Python realmente faz é alternar rapidamente entre diferentes threads em execução.
Muitas pessoas tentam argumentar para o Python que esses são os verdadeiros threads. 3 Isso é verdade, mas não muda o fato de que o Python lida com os threads de maneira diferente do que você esperaria.
A solução proposta é o uso de módulos de multiprocessamento. As classes de processos fornecidas pelos módulos de multiprocessamento podem, basicamente, cobrir bem as divergências. No entanto, as divergências são muito mais caras do que o custo do thread.
No entanto, este problema não é encontrado por todos os programas em Python. PyPy-stm é um exemplo de uma implementação do Python que não é afetada pelo GIL. Implementações baseadas em outras plataformas como JVM (Jython) ou CLR (IronPython) não têm problemas com o GIL.
Em suma, tenha cuidado ao usar a classe de threads, pois o que você está recebendo pode não ser o que você quer.
Existem dois tipos de classes no Python 2, as classes de estilo antigo e as classes de estilo novo. Se você usa o Python 3, então você está usando a classe de estilo novo padrão. Para garantir que você use o estilo novo em Python 2, você precisa herdar objetos ou quaisquer novas classes que você crie que nem sempre herdam a instrução int ou list.
class MyNewObject(object): # stuff here
Estas novas classes corrigem alguns problemas muito básicos que surgiram nas classes antigas, e se você estiver interessado em ver a documentação, você pode ver o que foi feito com as classes antigas.
Os seguintes erros são muito comuns entre os iniciantes:
for name_index in range(len(names)):
print(names[name_index])
É óbvio que não é necessário usar o len, e, na verdade, percorrer a lista pode ser feito com uma frase muito simples:
for name in names:
print(name)
Além disso, há uma série de outras ferramentas que você pode usar para simplificar a repetição. Por exemplo, o zip pode ser usado para percorrer duas listas:
for cat, dog in zip(cats, dogs):
print(cat, dog)
Se quisermos considerar as variáveis de índice e de lista de valores, podemos usar enumerate.
for index, cat in enumerate(cats):
print(cat, index)
Existem muitas opções de funções no itertools. Se o itertools tem o que você quer, é fácil de usar. Mas não use muito para usá-lo.
O abuso das itertools fez com que um dos grandes ícones do StackOverflow demorasse a resolver o problema.
Parâmetros padrão variáveis
Eu vi muitas dessas coisas:
def foo(a, b, c=[]):
# append to c
# do some more stuff
Não use parâmetros padrão variáveis, mas sim:
def foo(a, b, c=None):
if c is None:
c = []
# append to c
# do some more stuff
O exemplo a seguir pode ajudar a entender a questão de forma intuitiva:
In[2]: def foo(a, b, c=[]):
... c.append(a)
... c.append(b)
... print(c)
...
In[3]: foo(1, 1)
[1, 1]
In[4]: foo(1, 1)
[1, 1, 1, 1]
In[5]: foo(1, 1)
[1, 1, 1, 1, 1, 1]
O mesmo c é citado uma e outra vez a cada chamada da função. Isso pode ter algumas consequências muito desnecessárias.