Recursos ocultos do Python [fechado]


1419

Quais são os recursos menos conhecidos, mas úteis, da linguagem de programação Python?

  • Tente limitar as respostas ao núcleo do Python.
  • Um recurso por resposta.
  • Dê um exemplo e uma breve descrição do recurso, não apenas um link para a documentação.
  • Rotule o recurso usando um título como a primeira linha.

Links rápidos para respostas:

Respostas:


740

Operadores de comparação de encadeamento:

>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20 
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True

No caso de você está pensando que está fazendo 1 < x, que sai como True, e em seguida, comparando True < 10, que é também True, então não, isso não é realmente o que acontece (ver o último exemplo.) É realmente traduzindo-se 1 < x and x < 10, e x < 10 and 10 < x * 10 and x*10 < 100, mas com menos digitação e cada O termo é avaliado apenas uma vez.


121
Isso é muito útil. Deve ser padrão para todos os idiomas. Infelizmente, não é.
Stalepretzel 17/10/08

8
você deve adicionar alguns exemplos que retornam falso também. como >>> 10 <x <20 False #
ShoeLace

19
Isso também se aplica a outros operadores de comparação, e é por isso que às vezes as pessoas ficam surpresas porque o código como (5 em [5] é True) é False (mas não é sintético testar explicitamente contra booleanos como esse, para começar).
Miles

19
Bom, mas cuidado com a mesma precedência, como 'in' e '='. 'A em B == C em D' significa '(A em B) e (B == C) e (C em D)', o que pode ser inesperado.
Charles Merriam

15
Azafe: As comparações do Lisp funcionam naturalmente dessa maneira. Não é um caso especial, porque não há outra maneira (razoável) de interpretar (< 1 x 10). Você pode até mesmo aplicar-lhes argumentos individuais, como (= 10): cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/...
Ken

512

Obtenha a árvore de análise python regex para depurar seu regex.

Expressões regulares são um ótimo recurso do python, mas depurá-las pode ser uma dor, e é muito fácil cometer erros de regex.

Felizmente, o python pode imprimir a árvore de análise regex, passando o sinalizador não documentado, experimental e oculto re.DEBUG(na verdade, 128) para re.compile.

>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

Depois de entender a sintaxe, você poderá identificar seus erros. Não podemos ver que eu esqueci de escapar do []no [/font].

Obviamente, você pode combiná-lo com qualquer sinalizador que desejar, como regexes comentadas:

>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
 """, re.DEBUG|re.VERBOSE|re.DOTALL)

3
Exceto analisar o HTML usando expressões regulares é lento e doloroso. Mesmo o módulo analisador interno 'html' não usa expressões regulares para concluir o trabalho. E se o módulo html não lhe agradar, há muitos módulos analisadores XML / HTML que fazem o trabalho sem precisar reinventar a roda.
BatchyX 26/03/10

Um link para a documentação na sintaxe de saída seria ótimo.
Personman

1
Isso deve ser uma parte oficial do Python, não experimental ... O RegEx é sempre complicado e é capaz de rastrear o que está acontecendo.
Cahit

460

enumerar

Envolva um iterável com enumerar e ele produzirá o item junto com seu índice.

Por exemplo:


>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>

Referências:


56
Estou surpreso que isso não seja abordado rotineiramente nos tutoriais que falam sobre listas python.
Draemon

45
E todo esse tempo eu estava codificando desta maneira: para i no intervalo (len (a)): ... e depois usando um [i] para obter o item atual.
Fernando Martin

4
@Berry Tsakala: Que eu saiba, não foi preterido.
219 JAB

23
Caramba, isso é incrível. para i in xrange (len (a)): sempre foi meu idioma python menos favorito.
Personman

15
enumerate pode iniciar a partir de um índice arbitrário, não necessário 0. Exemplo: 'para i, item em enumerar ( lista , início = 1): imprima i, item' iniciará a enumeração de 1, não 0.
dmitry_romanov

419

Criando objetos geradores

Se você escrever

x=(n for n in foo if bar(n))

você pode sair do gerador e atribuí-lo a x. Agora isso significa que você pode fazer

for n in x:

A vantagem disso é que você não precisa de armazenamento intermediário, o que você precisaria se precisasse

x = [n for n in foo if bar(n)]

Em alguns casos, isso pode levar a uma velocidade significativa.

Você pode anexar muitas instruções if ao final do gerador, basicamente replicando aninhados para loops:

>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
...   print i 

(0, 4)
(0, 5)
(1, 4)
(1, 5)

Você também pode usar uma compreensão de lista aninhada para isso, sim?
Shapr

54
Destaca-se a economia de sobrecarga de memória. Os valores são calculados sob demanda, para que você nunca tenha todo o resultado da compreensão da lista na memória. Isso é particularmente desejável se, posteriormente, você iterar apenas parte da compreensão da lista.
Saffsd 17/05/09

19
Isso não é uma imagem particularmente "oculta", mas também vale a pena notar é o fato de que você não pode retroceder um objeto gerador, enquanto pode reiterar uma lista várias vezes.
susmits

13
O recurso "sem rebobinar" dos geradores pode causar alguma confusão. Especificamente, se você imprimir o conteúdo de um gerador para depuração e usá-lo posteriormente para processar os dados, ele não funcionará. Os dados são produzidos, consumidos por print () e, em seguida, não estão disponíveis para o processamento normal. Isso não se aplica às compreensões de lista, pois elas são completamente armazenadas na memória.
johntellsall

4
Resposta semelhante (duplamente): stackoverflow.com/questions/101268/hidden-features-of-python/… Observe, no entanto, que a resposta que eu vinculei aqui menciona uma apresentação MUITO BOM sobre o poder dos geradores. Você realmente deveria dar uma olhada.
Denilson Sá Maia

353

iter () pode usar um argumento que pode ser chamado

Por exemplo:

def seek_next_line(f):
    for c in iter(lambda: f.read(1),'\n'):
        pass

A iter(callable, until_value)função chama callablee produz repetidamente seu resultado até que until_valueseja retornada.


Como iniciante no python, você pode explicar por que a lambdapalavra-chave é necessária aqui?
SiegeX 12/08

@SiegeX sem o lambda, f.read (1) seria avaliado (retornando uma string) antes de ser passado para a função iter. Em vez disso, o lambda cria uma função anônima e a passa para o iter.
jmilloy

339

Cuidado com argumentos padrão mutáveis

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

Em vez disso, você deve usar um valor sentinela indicando "não fornecido" e substituir pelo mutável que você deseja como padrão:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

39
Esse é definitivamente um dos recursos ocultos mais desagradáveis. Eu me deparo com isso de vez em quando.
Torsten Marek

77
Achei isso muito mais fácil de entender quando soube que os argumentos padrão vivem em uma tupla que é um atributo da função, por exemplo foo.func_defaults. O que, sendo uma tupla, é imutável.
9788 Robert Rossney #

2
@ grayger: À medida que a instrução def é executada, seus argumentos são avaliados pelo intérprete. Isso cria (ou religa) um nome para um objeto de código (o conjunto da função). No entanto, os argumentos padrão são instanciados como objetos no momento da definição. Isso ocorre em qualquer momento do objeto padrão, mas apenas significativo (expondo a semântica visível) quando o objeto é mutável. Não há como vincular novamente esse nome de argumento padrão no fechamento da função, embora possa obviamente ser substituído por qualquer chamada ou a função inteira possa ser redefinida).
Jim Dennis

3
@ Robert, é claro que os argumentos da tupla podem ser imutáveis, mas os objetos para os quais apontam não são necessariamente imutáveis.
poolie

16
Um truque rápido para tornar sua inicialização um pouco mais curta: x = x ou []. Você pode usar isso em vez da instrução 2 if if.
Dave mankoff

317

Enviando valores para as funções do gerador . Por exemplo, tendo esta função:

def mygen():
    """Yield 5 until something else is passed back via send()"""
    a = 5
    while True:
        f = (yield a) #yield a and possibly get f in return
        if f is not None: 
            a = f  #store the new value

Você pode:

>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7)  #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7

Acordado. Vamos tratar isso como um exemplo desagradável de um recurso escondido de Python :)
Rafał Dowgird

89
Em outras línguas, acredito que esse dispositivo mágico é chamado de "variável".
finnw

5
as corotinas devem ser corotinas e o gerador também deve ser elas mesmas, sem misturar. Mega-ótimo link e conversa e exemplos sobre isso aqui: dabeaz.com/coroutines
u0b34a0f6ae 23/08/09

31
@innf: o exemplo implementa algo semelhante a uma variável. No entanto, o recurso pode ser usado de várias outras maneiras ... ao contrário de uma variável. Também deve ser óbvio que semânticas semelhantes podem ser implementadas usando objetos (uma classe que implemente o método de chamada do Python , em particular).
Jim Dennis

4
Este é um exemplo muito trivial para pessoas que nunca viram (e provavelmente não entenderão) co-rotinas. O exemplo que implementa a média atual sem risco de excesso de variável de soma é bom.
Prashant Kumar

313

Se você não gosta de usar espaço em branco para indicar escopos, pode usar o estilo C {} emitindo:

from __future__ import braces

122
Isso é mau. :)
Jason Baker

37
>>> do __future__ import chaves Arquivo "<stdin>", linha 1 SintaxeErro: sem chance: P
Benjamin W. Smith

40
isso é blasfêmia!
22130 Berk D. Demir

335
Acho que podemos ter um erro sintático aqui, não deveria ser "de chaves de importação __past__ "?
Bill K

47
de chaves de importação __cruft__
Phillip B Oldham

305

O argumento step em operadores de fatia. Por exemplo:

a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

O caso especial x[::-1]é um idioma útil para 'x invertido'.

>>> a[::-1]
[5,4,3,2,1]

31
muito mais clara, na minha opinião, é a função reversed (). >>> list (invertida (intervalo (4))) [3, 2, 1, 0]
Christian Oudard

3
então como escrever "this ia string" [:: - 1] de uma maneira melhor? doesnt invertida parece ajudar
Berry Tsakala

24
O problema com reversed () é que ele retorna um iterador; portanto, se você deseja preservar o tipo da sequência invertida (tupla, string, lista, unicode, tipos de usuário ...), é necessário uma etapa adicional para convertê-lo novamente .
Rafał Dowgird 24/06/09

6
def reverse_string (string): retorna string [:: - 1]
pi.

4
@pi Acho que se alguém souber o suficiente para definir reverse_string como você tem, poderá deixar o [:: - 1] no seu código e se sentir confortável com o significado e com a sensação de que é apropriado.
Physicsmichael

289

Decoradores

Os decoradores permitem agrupar uma função ou método em outra função que pode adicionar funcionalidade, modificar argumentos ou resultados, etc. Você escreve decoradores uma linha acima da definição da função, começando com um sinal de "arroba" (@).

O exemplo mostra um print_argsdecorador que imprime os argumentos da função decorada antes de chamá-la:

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo

54
Ao definir decoradores, recomendo decorar o decorador com @decorator. Ele cria um decorador que preserva uma assinatura de funções ao fazer uma introspecção nele. Mais informações aqui: phyast.pitt.edu/~micheles/python/documentation.html
sirwart

45
Como isso é um recurso oculto?
Vetle 02/10/08

50
Bem, ele não está presente na maioria dos tutoriais simples sobre Python, e eu me deparei com isso muito tempo depois de começar a usar o Python. Isso é o que eu chamaria de recurso oculto, praticamente o mesmo que outros posts principais aqui.
DzinX 03/10/08

16
No entanto, as perguntas pedem "recursos menos conhecidos, mas úteis, da linguagem de programação Python". Como você mede "recursos menos conhecidos, mas úteis"? Quero dizer, como essas respostas estão ocultas?
JohnD

4
@vetler A maioria das coisas aqui dificilmente está "escondida".
Humphrey Bogart

288

A sintaxe for ... else (consulte http://docs.python.org/ref/for.html )

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

O bloco "else" será normalmente executado no final do loop for, a menos que a interrupção seja chamada.

O código acima pode ser emulado da seguinte maneira:

found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found: 
    print("i was never 0")

218
Eu acho que a sintaxe for / else é estranha. Parece que a cláusula else deve ser executada se o corpo do loop nunca for executado.
Codeape 10/10/08

14
ah Nunca vi aquele! Mas devo dizer que é um pouco impróprio. Quem esperaria que o bloco else seja executado apenas se a interrupção nunca acontecer? Concordo com o codeape: parece que mais foi inserido para foos vazios.
Daren Thomas

52
Parece que a palavra-chave deve ser, finalmente, não outra coisa
Jiaaro

21
Exceto, finalmente, já é usado de uma maneira em que esse conjunto é sempre executado.

7
Definitivamente, não deve ser "mais". Talvez 'then' ou algo assim, e então 'else' para quando o loop nunca foi executado.
Tor Valamo

258

A partir de 2.5, os ditados têm um método especial __missing__que é chamado para itens ausentes:

>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
... 
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

Também existe uma subclasse dict collectionschamada, defaultdictque faz praticamente o mesmo, mas chama uma função sem argumentos para itens não existentes:

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

Eu recomendo converter esses dictos em ditados regulares antes de passá-los para funções que não esperam tais subclasses. Muitos códigos usam d[a_key]e capturam KeyErrors para verificar se existe um item que adicionaria um novo item ao ditado.


10
Eu prefiro usar setdefault. m = {}; m.setdefault ('foo', 1)
grayger

22
@grayger quis dizer isso m={}; m.setdefault('foo', []).append(1).
Cristian Ciupitu

1
No entanto, há casos em que a aprovação do padrão é muito útil. A função pode, por exemplo, repetir o valor e funciona para chaves indefinidas sem código extra, pois o padrão é uma lista vazia.
Marian

3
O defaultdict é melhor em algumas circunstâncias do que o setdefault, pois ele não cria o objeto padrão , a menos que a chave esteja ausente. setdefault o cria, independentemente de estar ausente ou não. Se o seu objeto padrão é caro para criar isso pode ser um problema de desempenho - obtive uma aceleração decente de um programa simplesmente alterando todas as chamadas de configuração padrão.
Whatang

2
defaultdicttambém é mais poderoso que o setdefaultmétodo em outros casos. Por exemplo, para uma contra- dd = collections.defaultdict(int) ... dd[k] += 1vs d.setdefault(k, 0) += 1.
Mike Graham

247

Troca de valor no local

>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

>>> a, b = b, a
>>> a, b
(5, 10)

O lado direito da atribuição é uma expressão que cria uma nova tupla. O lado esquerdo da tarefa descompacta imediatamente essa tupla (não referenciada) dos nomes ae b.

Após a atribuição, a nova tupla não é referenciada e marcada para coleta de lixo, e os valores vinculados ae bforam trocados.

Conforme observado na seção do tutorial do Python sobre estruturas de dados ,

Observe que a atribuição múltipla é realmente apenas uma combinação de empacotamento de tupla e descompactação de sequência.


1
Isso usa mais memória real do que a maneira tradicional? Eu acho que fazer, já que você está criando uma tupla, em vez de apenas uma variável de swap
Nathan

75
Não usa mais memória. Ele usa menos. Eu apenas escrevi para os dois lados e descompilei o bytecode. O compilador otimiza, como você esperaria. Esses resultados mostraram que ele está configurando os Vars e depois ROT_TWOing. ROT_TWO significa 'trocar os dois vars mais altos da pilha' ... Muito divertido, na verdade.
royal

5
Você também aponta inadvertidamente outro recurso interessante do Python, que é o de criar implicitamente uma tupla de itens apenas separando-os por vírgulas.
asmeurer

3
Dana the Sane: a atribuição em Python é uma declaração, não uma expressão, de modo que a expressão seria inválida se = tivesse maior prioridade (ou seja, fosse interpretada como a, (b = b), a).
Hb

5
Este é o recurso menos oculto que eu li aqui. Bom, mas descrito explicitamente em todos os tutoriais do Python.
Thiago Chaves

235

Expressões regulares legíveis

No Python, você pode dividir uma expressão regular em várias linhas, nomear suas correspondências e inserir comentários.

Exemplo de sintaxe detalhada (de Dive into Python ):

>>> pattern = """
... ^                   # beginning of string
... M{0,4}              # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                     #            or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                     #        or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                     #        or 5-8 (V, followed by 0 to 3 I's)
... $                   # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)

Exemplo de correspondências de nomeação (no HOWTO de Expressão Regular )

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'

Você também pode escrever uma regex verbalmente sem usar re.VERBOSEa concatenação literal de cadeias.

>>> pattern = (
...     "^"                 # beginning of string
...     "M{0,4}"            # thousands - 0 to 4 M's
...     "(CM|CD|D?C{0,3})"  # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                         #            or 500-800 (D, followed by 0 to 3 C's)
...     "(XC|XL|L?X{0,3})"  # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                         #        or 50-80 (L, followed by 0 to 3 X's)
...     "(IX|IV|V?I{0,3})"  # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                         #        or 5-8 (V, followed by 0 to 3 I's)
...     "$"                 # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"

7
Não sei se realmente consideraria um recurso Python, a maioria dos mecanismos de ER tem uma opção detalhada.
Jeremy Banks

18
Sim, mas como você não pode fazê-lo no grep ou na maioria dos editores, muitas pessoas não sabem que está lá. O fato de que outras línguas têm uma característica equivalente não o torna não um recurso útil e pouco conhecido de python
Mark Baker

7
Em um grande projeto com muitas expressões regulares otimizadas (leia-se: otimizadas para máquinas, mas não para seres humanos), mordi a bala e as converti em sintaxe detalhada. Agora, apresentar novos desenvolvedores a projetos é muito mais fácil. A partir de agora, aplicamos REs detalhados em todos os projetos.
22130 Berk D. Demir

Prefiro apenas dizer: centenas = "(CM | CD | D? C {0,3})" # 900 (CM), 400 (CD) etc. A linguagem já tem uma maneira de dar nomes às coisas, um maneira de adicionar comentários e uma maneira de combinar seqüências de caracteres. Por que usar a sintaxe especial da biblioteca aqui para coisas que a linguagem já faz perfeitamente bem? Parece ir diretamente contra Epigram Perlis' 9.
Ken

3
@ Ken: um regex nem sempre pode estar diretamente na fonte, pode ser lido nas configurações ou em um arquivo de configuração. Permitir comentários ou apenas espaço em branco adicional (para facilitar a leitura) pode ser uma grande ajuda.

222

Argumento de Função Descompactando

Você pode descompactar uma lista ou um dicionário como argumentos de função usando *e **.

Por exemplo:

def draw_point(x, y):
    # do some magic

point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}

draw_point(*point_foo)
draw_point(**point_bar)

Atalho muito útil, pois listas, tuplas e dictos são amplamente utilizados como contêineres.


27
* Também é conhecido como o operador splat
Gabriel

3
Eu gosto desse recurso, mas o pylint não infelizmente.
Stephen Paulger

5
o conselho de pylint não é uma lei. A outra maneira, apply (callable, arg_seq, arg_map), está obsoleta desde a versão 2.3.
Yann Vernier

1
o conselho de pylint pode não ser lei, mas é um bom conselho. Depurar código que se entrega excessivamente a coisas como essa é um inferno. Como observa o pôster original, esse é um atalho útil .
Andrew

2
Eu vi isso sendo usado no código uma vez e me perguntei o que ele fez. Infelizmente é difícil pesquisar no Google por "Python **"
Fraser Graham

205

ROT13 é uma codificação válida para o código fonte, quando você usa a declaração de codificação correta na parte superior do arquivo de código:

#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")

10
Ótimo! Observe como strings de bytes são tomadas literalmente, mas strings unicode são decodificados: trycevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae

12
infelizmente, ele foi removido do py3k
mykhal 19/12/2009

9
Isso é bom para ignorar antivírus.
31510 L'o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

96
Isso não tem nada a ver com a codificação, é apenas Python escrito em galês. :-P
Olivier Verdier 14/07

33
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!
Manuel Ferreria

183

Criando novos tipos de uma maneira totalmente dinâmica

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

que é exatamente o mesmo que

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

Provavelmente não é a coisa mais útil, mas é bom saber.

Edit : Nome fixo do novo tipo, deve ser NewTypeexatamente a mesma coisa que com a classinstrução.

Editar : ajustou o título para descrever com mais precisão o recurso.


8
Isso tem muito potencial de utilidade, por exemplo, JIT ORMs
Mark Cidade

8
Eu o uso para gerar classes HTML-Form com base em uma entrada dinâmica. Muito agradável!
pi.

15
Nota: todas as classes são criadas em tempo de execução. Portanto, você pode usar a instrução 'class' dentro de uma função condicional ou dentro de uma função (muito útil para criar famílias de classes ou classes que atuam como fechamento). A melhoria que o 'tipo' traz é a capacidade de definir com precisão um conjunto de atributos (ou bases) gerados dinamicamente.
Spookylukey 01/01

1
Você também pode criar tipos anônimos com uma cadeia em branco, como: tipo ( '', (objeto,), { 'x': 'blá'})
bluehavana

3
Pode ser muito útil para injeções de código.
Avihu Turzion

179

Gerentes de contexto e a withdeclaração " "

Introduzido no PEP 343 , um gerenciador de contexto é um objeto que atua como um contexto de tempo de execução para um conjunto de instruções.

Como o recurso faz uso de novas palavras-chave, é introduzido gradualmente: está disponível no Python 2.5 através da __future__diretiva. O Python 2.6 e superior (incluindo o Python 3) o disponibilizam por padrão.

Eu tenho usado muito a instrução "with" porque acho que é uma construção muito útil, aqui está uma demonstração rápida:

from __future__ import with_statement

with open('foo.txt', 'w') as f:
    f.write('hello!')

O que está acontecendo aqui nos bastidores é que a instrução "with" chama os métodos __enter__e especiais __exit__no objeto de arquivo. Os detalhes da exceção também são passados ​​para __exit__se alguma exceção foi levantada do corpo da instrução with, permitindo que o tratamento da exceção ocorra lá.

O que isso faz com você nesse caso específico é que garante que o arquivo seja fechado quando a execução estiver fora do escopo do withconjunto, independentemente se isso ocorrer normalmente ou se uma exceção foi lançada. É basicamente uma maneira de abstrair o código comum de tratamento de exceções.

Outros casos de uso comuns para isso incluem bloqueio com threads e transações com o banco de dados.


3
Eu não aprovaria uma revisão de código que importasse algo do futuro . Os recursos são mais bonitos do que úteis, e geralmente acabam confundindo os novatos em Python.
um nerd pago

6
Sim, recursos "fofos", como escopos e geradores aninhados, são melhores para quem sabe o que está fazendo. E qualquer pessoa que queira ser compatível com versões futuras do Python. Para escopos e geradores aninhados, "versões futuras" do Python significam 2.2 e 2.5, respectivamente. Para a declaração with, "versões futuras" do Python significa 2.6.
Chris B.

10
Isso pode ser desnecessário, mas com o python v2.6 +, você não precisa mais importar do futuro . agora é uma palavra-chave de primeira classe.
Fitzgeraldsteele

25
Em 2,7 você pode ter múltiplos withs:) with open('filea') as filea and open('fileb') as fileb: ...
Austin Richardson

5
@ Austin, não consegui que essa sintaxe funcionasse no 2.7. no entanto, isso funcionou: with open('filea') as filea, open('fileb') as fileb: ...
wim

168

Os dicionários têm um método get ()

Os dicionários têm um método 'get ()'. Se você d ['key'] e a chave não estiverem lá, você receberá uma exceção. Se você fizer d.get ('key'), retornará None se 'key' não estiver lá. Você pode adicionar um segundo argumento para recuperar esse item em vez de Nenhum, por exemplo: d.get ('key', 0).

É ótimo para coisas como somar números:

sum[value] = sum.get(value, 0) + 1


39
Além disso, faça o checkout do método setdefault.
Daren Thomas

27
Além disso, verifique a classe collections.defaultdict.
JFS

8
Se você estiver usando o Python 2.7 ou posterior, ou 3.1 ou posterior, consulte a classe Counter no módulo de coleções. docs.python.org/library/collections.html#collections.Counter
Elias Zamaria

Oh cara, esse tempo todo eu venho fazendo get(key, None). Não tinha idéia do que Noneera fornecido por padrão.
Jordan Reiter

152

Descritores

Eles são a mágica por trás de vários recursos principais do Python.

Quando você usa acesso pontilhado para procurar um membro (por exemplo, xy), o Python primeiro procura o membro no dicionário de instância. Se não for encontrado, ele o procura no dicionário de classes. Se o encontrar no dicionário de classes e o objeto implementar o protocolo do descritor, em vez de apenas devolvê-lo, o Python o executará. Um descritor é qualquer classe que implementa as __get__, __set__ou __delete__métodos.

Veja como você implementaria sua própria versão (somente leitura) da propriedade usando descritores:

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

e você o usaria exatamente como a propriedade interna ():

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

Os descritores são usados ​​no Python para implementar propriedades, métodos vinculados, métodos estáticos, métodos de classe e slots, entre outras coisas. Compreendê-los facilita ver por que muitas coisas que antes pareciam 'peculiaridades' do Python são do jeito que são.

Raymond Hettinger tem um excelente tutorial que faz um trabalho muito melhor de descrevê-los do que eu.


Esta é uma duplicata de decoradores, não é? ( stackoverflow.com/questions/101268/… )
gecco

2
não, decoradores e descritores são coisas totalmente diferentes, embora no código de exemplo eu esteja criando um decorador de descritor. :)
Nick Johnson

1
A outra maneira de fazer isso é com um lambda:foo = property(lambda self: self.__foo)
Pete Peterson

1
@PetePeterson Sim, mas propertyele próprio é implementado com descritores, que foi o ponto da minha postagem.
perfil completo de Nick Johnson

142

Atribuição Condicional

x = 3 if (y == 1) else 2

Ele faz exatamente o que parece: "atribua 3 a x se y for 1; caso contrário, atribua 2 a x". Observe que os parênteses não são necessários, mas eu gosto deles para facilitar a leitura. Você também pode encadeá-lo se tiver algo mais complicado:

x = 3 if (y == 1) else 2 if (y == -1) else 1

Embora em um certo ponto, vá um pouco longe demais.

Observe que você pode usar if ... else em qualquer expressão. Por exemplo:

(func1 if y == 1 else func2)(arg1, arg2) 

Aqui, func1 será chamado se y for 1 e func2, caso contrário. Nos dois casos, a função correspondente será chamada com os argumentos arg1 e arg2.

Analogamente, o seguinte também é válido:

x = (class1 if y == 1 else class2)(arg1, arg2)

onde class1 e class2 são duas classes.


29
A atribuição não é a parte especial. Você poderia facilmente fazer algo como: retorno 3 se (y == 1) else 2.
Brian

25
Essa maneira alternativa é a primeira vez que vi Python ofuscado.
Craig McQueen

3
Kylebrooks: Nesse caso, os operadores booleanos causam um curto-circuito. Ele avaliará apenas 2 se bool (3) == False.
12269 RoadieRich

15
essa codificação de estilo inverso me confunde. algo como x = ((y == 1) ? 3 : 2)faz mais sentido para mim
MPEN

13
Eu sinto exatamente o oposto do @Mark, os operadores ternários do estilo C sempre me confundiram; é o lado direito ou o meio que é avaliado em uma condição falsa? Eu prefiro a sintaxe ternária do Python.
11139 Jeffrey Harris

141

Doctest : documentação e testes de unidade ao mesmo tempo.

Exemplo extraído da documentação do Python:

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

6
Certamente os exames são legais, mas eu realmente não gosto de todo o problema que você precisa digitar para testar se algo deve gerar uma exceção
TM.

60
Os exames são superestimados e poluem a documentação. Com que frequência você testa uma função autônoma sem nenhum setUp ()?
um nerd pago

2
quem disse que você não pode ter a configuração em um doctest? escrever uma função que gera o contexto e retorna locals(), em seguida, em sua doctest fazer locals().update(setUp())= D
Jiaaro

12
Se uma função autônoma requer um setUp, são grandes as chances de ela ser dissociada de algum material não relacionado ou colocada em uma classe. O namespace doctest da classe pode ser reutilizado nos testes do método da classe, por isso é um pouco como setUp, apenas DRY e legível.
precisa saber é o seguinte

4
"Quantas vezes você testa uma função autônoma" - lotes. Acho que os documentos geralmente emergem naturalmente do processo de design quando estou decidindo sobre fachadas.
11111 Gregg Lind

138

Formatação nomeada

A formatação% usa um dicionário (também aplica a validação% i /% s etc.).

>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.

>>> foo, bar = 'question', 123

>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.

E como locals () também é um dicionário, você pode simplesmente passar isso como um ditado e ter% -substitions de suas variáveis ​​locais. Eu acho que isso é desaprovado, mas simplifica as coisas ..

Nova formatação de estilo

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))

60
Será eliminado gradualmente e, eventualmente, substituído pelo método format () da string.
Constantin

3
Formatação chamado é muito útil para tradutores como eles tendem a ver apenas a cadeia de formato, sem os nomes das variáveis para contexto
pixelbeat

2
Parece funcionar no python 3.0.1 (necessário para adicionar parênteses em torno da chamada de impressão).
Pasi Savolainen

9
um hash , hein? Eu vejo de onde você veio.
shylent 14/11/2009

11
A formatação% s não será eliminada gradualmente. str.format () é certamente mais pythonico, no entanto, na verdade, é 10x mais lento para a simples substituição de strings. Minha opinião é que% s formatação ainda é uma prática recomendada.
Kenneth Reitz

132

Para adicionar mais módulos python (especialmente os de terceiros), a maioria das pessoas parece usar variáveis ​​de ambiente PYTHONPATH ou adiciona links simbólicos ou diretórios em seus diretórios de pacotes de sites. Outra maneira é usar arquivos * .pth. Aqui está a explicação oficial do documento python:

"A maneira mais conveniente [de modificar o caminho de pesquisa do python] é adicionar um arquivo de configuração do caminho a um diretório que já está no caminho do Python, geralmente ao diretório ... / site-packages /. Os arquivos de configuração do caminho têm uma extensão .pth , e cada linha deve conter um único caminho que será anexado ao sys.path. (Como os novos caminhos são anexados ao sys.path, os módulos nos diretórios adicionados não substituirão os módulos padrão. Isso significa que você não pode usar esse mecanismo para instalar versões fixas de módulos padrão.) "


1
Eu nunca fiz a conexão entre esse arquivo .pth no diretório site-packages do setuptools e essa ideia. impressionante.
Dave paola

122

Cláusula Exception else :

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

O uso da cláusula else é melhor do que adicionar código adicional à cláusula try, pois evita a captura acidental de uma exceção que não foi gerada pelo código sendo protegido pela instrução try ... exceto.

Consulte http://docs.python.org/tut/node10.html


8
+1 isso é incrível. Se o bloco try for executado sem inserir nenhum bloco de exceção, o bloco else será inserido. E depois, claro, o bloco finally é executado
inspectorG4dget

Finalmente entendo por que o 'mais' está lá! Obrigado.
Taynaron

Seria mais sensato usar continue, mas acho que já foi usado;) #
214 Paweł Prażak

Observe que nas versões mais antigas do Python2 você não pode ter as duas outras: e, finalmente, cláusulas para a mesma tentativa: block
Kevin Horn

1
@ Paweł Prażak, como Kevin Horn mencionou, essa sintaxe foi introduzida após o lançamento inicial do Python e a adição de novas palavras-chave reservadas à linguagem existente é sempre problemática. É por isso que uma palavra-chave existente geralmente é reutilizada (cf "auto" no recente padrão C ++).
Constantin

114

Redigitando exceções :

# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

A instrução 'raise' sem argumentos dentro de um manipulador de erros diz ao Python para aumentar novamente a exceção com o traceback original intacto , permitindo que você diga "oh, desculpe, desculpe, não pretendi pegar isso, desculpe, desculpe. "

Se você deseja imprimir, armazenar ou mexer no traceback original, pode obtê-lo com sys.exc_info (), e imprimi-lo como o Python faria com o módulo 'traceback'.


Desculpe, mas esse é um recurso conhecido e comum em quase todos os idiomas.
Lucas S.

6
Observe o texto em itálico. Algumas pessoas o farão raise e, o que não preserva o retorno original.
habnabit

12
Talvez mais mágico, exc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]é equivalente a isso, mas você pode alterar esses valores ao redor (por exemplo, alterar o tipo de exceção ou mensagem)
BNAI

3
@ Lucas S. Bem, eu não sabia, e estou feliz que está escrito aqui.
e-satis 23/06

i pode estar mostrando minha juventude aqui, mas eu sempre usei a sintaxe python 3 em Python 2.7 com nenhum problema
wim

106

Mensagens principais :)

import this
# btw look at this module's source :)

Decifrado :

O Zen de Python, de Tim Peters

Bonito é melhor que feio.
Explícito é melhor que implícito.
Simples é melhor que complexo.
Complexo é melhor que complicado.
Flat é melhor que aninhado.
Esparso é melhor que denso.
Legibilidade conta.
Casos especiais não são especiais o suficiente para violar as regras.
Embora praticidade supere a pureza.
Os erros nunca devem passar silenciosamente.
A menos que seja explicitamente silenciado.
Diante da ambiguidade, recuse a tentação de adivinhar. Deve haver uma - e preferencialmente apenas uma - maneira óbvia de fazê-lo.
Embora esse caminho possa não ser óbvio a princípio, a menos que você seja holandês.
Agora é melhor do que nunca.
Embora nunca seja frequentemente melhor do queagora mesmo .
Se a implementação é difícil de explicar, é uma má ideia.
Se a implementação é fácil de explicar, pode ser uma boa ideia.
Os espaços para nome são uma ótima idéia - vamos fazer mais!


1
Alguma idéia de por que a fonte foi codificada dessa maneira? Foi apenas por diversão, ou houve algum outro motivo?
MiniQuark

42
a maneira como a fonte é escrita vai contra o zen!
hasen


2
Atualizei meu /usr/lib/python2.6/this.py substituindo o código antigo por esse print s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256)))e ele parece muito melhor agora! :-D
fortran

2
@MiniQuark: lição de história rápida: wefearchange.org/2010/06/import-this-and-zen-of-python.html

105

Conclusão da guia Interpretador interativo

try:
    import readline
except ImportError:
    print "Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print "my function"
... 
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

Você também precisará definir uma variável de ambiente PYTHONSTARTUP.


2
Este é um recurso muito útil. Tanto é assim que eu tenho um script simples para habilitá-lo (mais um par de outras melhorias introspecção): pixelbeat.org/scripts/inpy
pixelbeat

43
IPython dá-lhe este, mais toneladas de outras coisas legais
akaihola

Isso teria sido mais útil no prompt pdb do que no prompt python normal (já que o IPython serve a esse propósito de qualquer maneira). No entanto, isso não parece funcionar no prompt do pdb, provavelmente porque o pdb vincula sua própria guia (o que é menos útil). Tentei chamar parse_and_bind () no prompt pdb, mas ainda não funcionou. A alternativa de obter o prompt do pdb com o IPython é mais trabalhoso, então eu tendem a não usá-lo.
haridsv

2
@haridsv - easy_install ipdb- então você pode usarimport ipdb; ipdb.set_trace()
Doug Harris

1
No OSX [e eu imagino que outros sistemas que utilizam libedit] você tem que fazerreadline.parse_and_bind ("bind ^I rl_complete")
Foo Bah

91

Compreensões de lista aninhadas e expressões geradoras:

[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

Eles podem substituir grandes pedaços de código de loop aninhado.


"para j no intervalo (i)" - isso é um erro de digitação? Normalmente você deseja intervalos fixos para iej. Se você estiver acessando uma matriz 2D, perderá metade dos seus elementos.
29720 Peter Gibson

Não estou acessando nenhuma matriz neste exemplo. O único objetivo deste código é mostrar que as expressões dos intervalos internos podem acessar aquelas dos intervalos externos. O subproduto é uma lista de pares (x, y) tais que 4> x> y> 0.
Rafał Dowgird 30/03/09

2
tipo como dupla integração no cálculo ou soma dupla.
29339 Yoo

22
O ponto principal a ser lembrado aqui (o que demorou muito tempo para perceber) é que a ordem das forinstruções deve ser escrita na ordem em que você espera que sejam escritas em um loop for padrão, de fora para dentro.
Sykora

2
Para acrescentar ao comentário de sykora: imagine que você está começando com uma pilha de fors e ifs com yield xinterior. Para converter isso em uma expressão de gerador, mova xprimeiro, exclua todos os dois pontos (e o yield) e coloque tudo entre parênteses. Para compreender a lista, substitua as parênteses externas por colchetes.
Ken Arnold

91

Sobrecarga do operador para o setbuiltin:

>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}

Mais detalhes da referência da biblioteca padrão: Tipos de conjunto


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.