Objetos semelhantes a arquivos são objetos em Python que se comportam como um arquivo real, por exemplo, têm um método read () e um método write (), mas têm uma implementação diferente. É uma realização do conceito Duck Typing .
É considerada uma boa prática permitir um objeto semelhante a um arquivo em todos os lugares onde um arquivo é esperado para que, por exemplo, um objeto StringIO ou um objeto Socket possa ser usado em vez de um arquivo real. Portanto, é ruim realizar uma verificação como esta:
if not isinstance(fp, file):
raise something
Qual é a melhor maneira de verificar se um objeto (por exemplo, um parâmetro de um método) é "semelhante a um arquivo"?
why
o que acontece com os operadores como__add__
,__lshift__
ou__or__
em classes personalizadas? (objeto de arquivo e API: docs.python.org/glossary.html#term-file-object )Para 3.1+, um dos seguintes:
Para 2.x, "objeto semelhante a arquivo" é uma coisa muito vaga para verificar, mas a documentação para qualquer função (ões) com a qual você está lidando, esperançosamente, dirá o que eles realmente precisam; se não, leia o código.
Como outras respostas apontam, a primeira coisa a se perguntar é o que exatamente você está verificando. Normalmente, o EAFP é suficiente e mais idiomático.
O glossário diz "arquivo-como objeto" é sinônimo de "objeto de arquivo", que em última análise significa que é uma instância de uma das três classes base abstratas definidas no o
io
módulo , que são eles próprios todas as subclasses deIOBase
. Portanto, a forma de verificar é exatamente como mostrado acima.(No entanto, a verificação
IOBase
não é muito útil. Você pode imaginar um caso em que você precisa distinguir um arquivo realread(size)
de alguma função de um argumento chamadaread
que não é semelhante a um arquivo, sem precisar também distinguir entre arquivos de texto e raw arquivos binários? Então, na verdade, você quase sempre deseja verificar, por exemplo, "é um objeto de arquivo de texto", não "é um objeto semelhante a um arquivo".)Para 2.x, embora o
io
módulo exista desde 2.6+, os objetos de arquivo embutidos não são instâncias deio
classes, nem qualquer um dos objetos semelhantes a arquivos no stdlib, nem a maioria dos objetos semelhantes a arquivos de terceiros que você é provável que encontre. Não havia uma definição oficial do que significa "objeto semelhante a um arquivo"; é apenas "algo como um objeto de arquivo embutido ", e funções diferentes significam coisas diferentes por "curtir". Essas funções devem documentar o que significam; se não, você deve olhar o código.No entanto, os significados mais comuns são "tem
read(size)
", "temread()
" ou "é um iterável de strings", mas algumas bibliotecas antigas podem esperar emreadline
vez de um desses, algumas bibliotecas gostam declose()
arquivos que você fornece, alguns esperam que sefileno
está presente, então outra funcionalidade está disponível, etc. E da mesma forma parawrite(buf)
(embora haja muito menos opções nessa direção).fonte
IOBase
. Por exemplo, as luminárias pytest fornecem o_pytest.capture.EncodedFile
que não herda de nada.Como outros já disseram, você geralmente deve evitar tais verificações. Uma exceção é quando o objeto pode ser legitimamente de tipos diferentes e você deseja um comportamento diferente dependendo do tipo. O método EAFP nem sempre funciona aqui, pois um objeto pode se parecer com mais de um tipo de pato!
Por exemplo, um inicializador pode pegar um arquivo, string ou instância de sua própria classe. Você pode então ter um código como:
Usar o EAFP aqui pode causar todos os tipos de problemas sutis, pois cada caminho de inicialização é executado parcialmente antes de lançar uma exceção. Essencialmente, essa construção imita a sobrecarga de função e, portanto, não é muito Pythônica, mas pode ser útil se usada com cuidado.
Como uma observação lateral, você não pode fazer a verificação de arquivo da mesma maneira no Python 3. Você precisará de algo como
isinstance(f, io.IOBase)
.fonte
O paradigma dominante aqui é EAFP: mais fácil pedir perdão do que permissão. Vá em frente e use a interface de arquivo e, a seguir, trate a exceção resultante ou deixe-as se propagarem para o chamador.
fonte
x
não for semelhante a um arquivo,x.read()
gerará sua própria exceção. Por que escrever uma declaração if extra? Basta usar o objeto. Vai funcionar ou quebrar.Geralmente é útil levantar um erro verificando uma condição, quando esse erro normalmente não seria levantado até muito mais tarde. Isso é especialmente verdadeiro para o limite entre o código 'terreno do usuário' e 'api'.
Você não colocaria um detector de metais em uma delegacia de polícia na porta de saída, mas sim na entrada! Se não verificar uma condição significa que pode ocorrer um erro que poderia ter sido detectado 100 linhas antes, ou em uma superclasse em vez de ser gerado na subclasse, então eu digo que não há nada de errado com a verificação.
Verificar os tipos adequados também faz sentido quando você está aceitando mais de um tipo. É melhor levantar uma exceção que diz "Eu preciso de uma subclasse de cadeia de base, arquivo OR" do que apenas lançar uma exceção porque alguma variável não tem um método de 'busca' ...
Isso não significa que você enlouqueça e faça isso em todos os lugares, na maioria das vezes eu concordo com o conceito de exceções se levantando, mas se você puder tornar sua API drasticamente clara ou evitar a execução desnecessária de código porque uma condição simples não foi atendida faça isso!
fonte
Você pode tentar chamar o método e capturar a exceção:
Se você deseja apenas um método de leitura e gravação, pode fazer o seguinte:
Se eu fosse você, escolheria o método try / except.
fonte
try
é sempre a primeira escolha. Oshasattr
cheques são apenas - por algum motivo realmente obscuro - você não pode simplesmente usartry
.fp.read(0)
vez defp.read()
para evitar colocar todo o código notry
bloco se quiser processar os dadosfp
posteriormente.fp.read()
arquivos grandes aumentam imediatamente o uso de memória.Flask
eu fiz isso e percebi que oFileStorage
objeto subjacente precisava de seu ponteiro redefinido após ser lido.Na maioria das circunstâncias, a melhor maneira de lidar com isso é não. Se um método pega um objeto semelhante a um arquivo e descobre que o objeto que foi passado não é, a exceção que é gerada quando o método tenta usar o objeto não é menos informativa do que qualquer exceção que você possa ter levantado explicitamente.
Porém, há pelo menos um caso em que você pode querer fazer esse tipo de verificação e é quando o objeto não está sendo usado imediatamente pelo que você o passou, por exemplo, se está sendo definido no construtor de uma classe. Nesse caso, eu acho que o princípio do EAFP é superado pelo princípio de "falha rápida". Eu verificaria o objeto para ter certeza de que implementou os métodos de que minha classe precisa (e que eles são métodos), por exemplo:
fonte
getattr(file, 'read')
vez de apenasfile.read
? Isso faz exatamente a mesma coisa.file
instância real . (Métodos de instâncias de tipos de extensão embutida / C são do tipobuiltin_function_or_method
, enquanto aqueles de classes de estilo antigo sãoinstancemethod
). O fato de que esta é uma classe de estilo antigo, e que ela usa==
em tipos em vez deininstance
ouissubclass
, são problemas adicionais, mas se a ideia básica não funcionar, isso pouco importa.Acabei encontrando sua pergunta quando estava escrevendo um
open
função semelhante a ela que poderia aceitar um nome de arquivo, descritor de arquivo ou objeto semelhante a arquivo pré-aberto.Em vez de testar um
read
método, como sugerem as outras respostas, acabei verificando se o objeto pode ser aberto. Se puder, é uma string ou descritor, e eu tenho um objeto semelhante a um arquivo válido em mãos do resultado. Seopen
gerar umTypeError
, o objeto já é um arquivo.fonte