Pergunta

Me deparei com o Python with declaração pela primeira vez hoje.Estou usando Python levemente por vários meses e nem sabia de sua existência!Dada a sua um tanto obscuro status, eu pensei que seria a pena perguntar:

  1. O que é Python with declaração projetado para ser usado?
  2. O que fazer você usá-lo?
  3. Há alguma dicas que eu preciso estar ciente de, ou comum anti-padrões associados seu uso?Todos os casos em que é melhor usar try..finally de with?
  4. Por que não é usado mais amplamente?
  5. Que padrão de uma biblioteca de classes são compatíveis com ele?
Foi útil?

Solução

  1. Eu acredito que isso já foi respondido por outros usuários antes de mim, então eu só o adiciono por uma questão de completude: o with A declaração simplifica o manuseio de exceções, encapsulando tarefas de preparação e limpeza comuns na chamada Gerentes de contexto. Mais detalhes podem ser encontrados em PEP 343. Por exemplo, o open A declaração é um gerente de contexto em si, que permite abrir um arquivo, mantenha -o aberto enquanto a execução estiver no contexto do with Declaração onde você a usou e feche -a assim que deixar o contexto, não importa se você o deixou devido a uma exceção ou durante o fluxo de controle regular. o with a declaração pode assim ser usada de maneiras semelhantes ao Padrão Raii em C ++: algum recurso é adquirido pelo with declaração e liberado quando você sai do with contexto.

  2. Alguns exemplos são: abrindo arquivos usando with open(filename) as fp:, adquirindo bloqueios usando with lock: (Onde lock é uma instância de threading.Lock). Você também pode construir seus próprios gerentes de contexto usando o contextmanager decorador de contextlib. Por exemplo, costumo usar isso quando tenho que alterar o diretório atual temporariamente e depois voltar para onde estava:

    from contextlib import contextmanager
    import os
    
    @contextmanager
    def working_directory(path):
        current_dir = os.getcwd()
        os.chdir(path)
        try:
            yield
        finally:
            os.chdir(current_dir)
    
    with working_directory("data/stuff"):
        # do something within data/stuff
    # here I am back again in the original working directory
    

    Aqui está outro exemplo que redireciona temporariamente sys.stdin, sys.stdout e sys.stderr Para outra manipulação de arquivos e os restaura mais tarde:

    from contextlib import contextmanager
    import sys
    
    @contextmanager
    def redirected(**kwds):
        stream_names = ["stdin", "stdout", "stderr"]
        old_streams = {}
        try:
            for sname in stream_names:
                stream = kwds.get(sname, None)
                if stream is not None and stream != getattr(sys, sname):
                    old_streams[sname] = getattr(sys, sname)
                    setattr(sys, sname, stream)
            yield
        finally:
            for sname, stream in old_streams.iteritems():
                setattr(sys, sname, stream)
    
    with redirected(stdout=open("/tmp/log.txt", "w")):
         # these print statements will go to /tmp/log.txt
         print "Test entry 1"
         print "Test entry 2"
    # back to the normal stdout
    print "Back to normal stdout again"
    

    E, finalmente, outro exemplo que cria uma pasta temporária e a limpa ao sair do contexto:

    from tempfile import mkdtemp
    from shutil import rmtree
    
    @contextmanager
    def temporary_dir(*args, **kwds):
        name = mkdtemp(*args, **kwds)
        try:
            yield name
        finally:
            shutil.rmtree(name)
    
    with temporary_dir() as dirname:
        # do whatever you want
    

Outras dicas

Eu sugeriria duas palestras interessantes:

  • PEP 343 A declaração "com"
  • Effbot Compreendendo a declaração de Python "com"

1.o with A instrução é usada para envolver a execução de um bloco com métodos definidos por um gerenciador de contexto. Isso permite comum try...except...finally Padrões de uso a serem encapsulados para reutilização conveniente.

2.Você poderia fazer algo como:

with open("foo.txt") as foo_file:
    data = foo_file.read()

OU

from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
   do_something()

Ou (Python 3.1)

with open('data') as input_file, open('result', 'w') as output_file:
   for line in input_file:
     output_file.write(parse(line))

OU

lock = threading.Lock()
with lock:
    # Critical section of code

3.Eu não vejo nenhum antipateria aqui.
Citando Mergulhe em python:

Tente .. finalmente é bom. com é melhor.

4.Eu acho que está relacionado ao hábito dos programadores usar try..catch..finally declaração de outros idiomas.

O Python with declaração de integrado de suporte ao idioma do Resource Acquisition Is Initialization expressão comumente usada em C++.Destina-se a permitir a segura aquisição e liberação de recursos do sistema operacional.

O with instrução cria recursos dentro de um escopo/bloco.Tem de escrever seu código utilizando os recursos dentro do bloco.Quando o bloco sai os recursos estão corretamente lançados, independentemente do resultado do código no bloco (isto é, se o bloco sai normalmente ou devido a uma exceção).

Muitos recursos na biblioteca em Python que obedecer o protocolo exigido pelo with instrução e assim pode ser usado com ele out-of-the-box.No entanto, qualquer pessoa pode fazer de recursos que pode ser usada em uma instrução com implementando o bem documentado protocolo: PEP 0343

Use sempre que você adquirir recursos na sua aplicação, que deve ser explicitamente abandonada, tais como arquivos, conexões de rede, bloqueios e afins.

Um exemplo de um antipateria pode ser usar o with dentro de um loop, quando seria mais eficiente ter o with fora do loop

por exemplo

for row in lines:
    with open("outfile","a") as f:
        f.write(row)

vs.

with open("outfile","a") as f:
    for row in lines:
        f.write(row)

A primeira maneira é abrir e fechar o arquivo para cada row O que pode causar problemas de desempenho em comparação com a segunda maneira com o Open e fecha o arquivo apenas uma vez.

Novamente para completar, adicionarei meu caso de uso mais útil para with declarações.

Eu faço muita computação científica e, para algumas atividades, preciso do Decimal Biblioteca para cálculos de precisão arbitrária. Alguma parte do meu código, preciso de alta precisão e, para a maioria das outras peças, preciso de menos precisão.

Defino minha precisão padrão para um número baixo e depois uso with Para obter uma resposta mais precisa para algumas seções:

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

Eu uso muito isso com o teste hipergeométrico, que requer a divisão de grandes números resultantes de fatores de formulários. Quando você faz cálculos de escala genômica, você deve ter cuidado com os erros de reversão e transbordamento.

Ver PEP 343 - A declaração 'com', há uma seção de exemplo no final.

... nova declaração "com" para o idioma python para possibilitar o uso de usos padrão das instruções Try/Finalmente.

Pontos 1, 2 e 3 sendo razoavelmente bem cobertos:

4: É relativamente novo, disponível apenas em python2.6+ (ou python2.5 usando from __future__ import with_statement)

A declaração com a declaração funciona com os chamados gerentes de contexto:

http://docs.python.org/release/2.5.2/lib/typecontextmanager.html

A idéia é simplificar o manuseio de exceções fazendo a limpeza necessária depois de deixar o bloco 'com'. Alguns dos but-ins python já funcionam como gerentes de contexto.

Outro exemplo para o suporte fora da caixa e um que pode ser um pouco desconcertante no começo quando você está acostumado à maneira como embutida open() se comporta, são connection Objetos de módulos populares de banco de dados, como:

o connection Objetos são gerentes de contexto e, como tal with-statement, no entanto, ao usar as opções acima, observe que:

Quando o with-block está terminado, seja com uma exceção ou sem, A conexão não está fechada. No caso de with-block Acabamentos com uma exceção, a transação é revertida, caso contrário, a transação será cometida.

Isso significa que o programador precisa tomar cuidado para fechar a conexão, mas permite adquirir uma conexão e usá -la em múltiplos with-statements, como mostrado no Psycopg2 Docs:

conn = psycopg2.connect(DSN)

with conn:
    with conn.cursor() as curs:
        curs.execute(SQL1)

with conn:
    with conn.cursor() as curs:
        curs.execute(SQL2)

conn.close()

No exemplo acima, você notará que o cursor objetos de psycopg2 também são gerentes de contexto. Da documentação relevante sobre o comportamento:

Quando um cursor sai do with-block Está fechado, liberando qualquer recurso eventualmente associado a ele. O estado da transação não é afetado.

Em python geralmente “com”A instrução é usada para abrir um arquivo, processar os dados presentes no arquivo e também para fechar o arquivo sem chamar um método Close (). A declaração "com" simplifica o manuseio de exceção, fornecendo atividades de limpeza.

Forma geral de com:

with open(“file name”, “mode”) as file-var:
    processing statements

Nota: Não há necessidade de fechar o arquivo ligando para Close () Após File-Var.close ()

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top