developer tip

객체가 Python에서 파일과 유사한 지 확인

copycodes 2020. 9. 18. 08:20
반응형

객체가 Python에서 파일과 유사한 지 확인


파일 류 객체 는 실제 파일처럼 동작하는 파이썬의 객체입니다. 예를 들어 read () 및 write method ()가 있지만 구현이 다릅니다. 이것은 Duck Typing 개념의 실현입니다 .

예를 들어 StringIO 또는 Socket 객체가 실제 파일 대신 사용될 수 있도록 파일이 예상되는 모든 곳에서 파일 류 객체를 허용하는 것이 좋습니다 . 따라서 다음과 같은 검사를 수행하는 것은 좋지 않습니다.

if not isinstance(fp, file):
   raise something

객체 (예 : 메소드의 매개 변수)가 "파일과 유사한"것인지 확인하는 가장 좋은 방법은 무엇입니까?


특별한 요구 사항이없는 한 일반적으로 코드에서 이와 같은 검사를 수행하는 것은 좋지 않습니다.

Python에서 타이핑은 동적입니다. 객체가 파일 인 것처럼 사용하고 결과 오류를 처리하는 대신 객체가 파일과 같은지 확인해야하는 이유는 무엇입니까?

당신이 할 수있는 모든 검사는 어쨌든 런타임에 일어날 것입니다. 그래서 같은 일을하고 if not hasattr(fp, 'read')어떤 예외를 fp.read()발생시키는 것은 메소드가 존재하지 않는 경우 결과 속성 오류를 호출 하고 처리하는 것보다 약간 더 유용 합니다.


3.1+의 경우 다음 중 하나 :

isinstance(something, io.TextIOBase)
isinstance(something, io.BufferedIOBase)
isinstance(something, io.RawIOBase)
isinstance(something, io.IOBase)

2.x의 경우 "파일 류 객체"는 확인하기에는 너무 모호하지만, 어떤 기능을 다루고 있는지에 대한 문서는 실제로 필요한 것이 무엇인지 알려줄 것입니다. 그렇지 않은 경우 코드를 읽으십시오.


다른 답변이 지적했듯이 가장 먼저 물어볼 것은 정확히 무엇을 확인하고 있는지입니다. 일반적으로 EAFP는 충분하고 관용적입니다.

용어집은 "개체와 같은 파일이"궁극적으로 세 가지 중 하나의 인스턴스를 의미합니다 "파일 객체"에 대한 동의어 말한다 추상 기본 클래스 에 정의 된 모듈 스스로 모든 서브 클래스, . 따라서 확인하는 방법은 위와 같습니다.ioIOBase

(그러나 검사 IOBase는 그다지 유용하지 않습니다. 텍스트 파일과 원시 파일을 구분할 필요없이 실제 파일과 유사한 read(size)이름의 일부 단일 인수 함수 를 구분해야하는 경우를 상상할 수 있습니까? read바이너리 파일입니까? 그래서 실제로는 거의 항상 "is a file-like object"가 아니라 "is a text file object"를 확인하고 싶습니다.)


2.x의 경우 io모듈이 2.6 이상부터 존재했지만 내장 파일 객체는 io클래스의 인스턴스가 아니며 stdlib에있는 파일 류 객체도 아니며 대부분의 타사 파일 류 객체도 아닙니다. 만날 가능성이 있습니다. "파일 류 객체"가 의미하는 바에 대한 공식적인 정의는 없습니다. 그것은 단지 "내장 파일 객체 와 같은 것 "이고, 다른 기능은 "like"에 의해 다른 것을 의미합니다. 이러한 기능은 그 의미를 문서화해야합니다. 그렇지 않은 경우 코드를 확인해야합니다.

그러나 가장 일반적인 의미는 "has read(size)", "has read()"또는 "is an iterable of strings"이지만, 일부 오래된 라이브러리는 readline그 중 하나 대신 기대할 수 있습니다 . 일부 라이브러리는 close()사용자가 제공하는 파일을 좋아 합니다. fileno존재하면 다른 기능을 사용할 수 있습니다. 그리고 유사하게 write(buf)(그 방향으로는 훨씬 적은 수의 옵션이 있지만).


다른 사람들이 말했듯이 일반적으로 이러한 검사를 피해야합니다. 한 가지 예외는 개체가 합법적으로 다른 유형일 수 있고 유형에 따라 다른 동작을 원하는 경우입니다. EAFP 방법은 객체가 둘 이상의 유형의 오리처럼 보일 수 있으므로 여기서 항상 작동하는 것은 아닙니다!

예를 들어 이니셜 라이저는 파일, 문자열 또는 자체 클래스의 인스턴스를 취할 수 있습니다. 그러면 다음과 같은 코드가있을 수 있습니다.

class A(object):
    def __init__(self, f):
        if isinstance(f, A):
            # Just make a copy.
        elif isinstance(f, file):
            # initialise from the file
        else:
            # treat f as a string

여기서 EAFP를 사용하면 각 초기화 경로가 예외를 발생시키기 전에 부분적으로 실행되므로 모든 종류의 미묘한 문제가 발생할 수 있습니다. 본질적으로이 구조는 함수 오버로딩을 모방하므로 Pythonic은 아니지만주의해서 사용하면 유용 할 수 있습니다.

참고로 Python 3에서 같은 방식으로 파일 검사를 수행 할 수 없습니다 isinstance(f, io.IOBase). 대신 다음과 같은 것이 필요 합니다.


여기서 지배적 인 패러다임은 EAFP입니다. 허가보다 용서를 구하기가 더 쉽습니다. 계속해서 파일 인터페이스를 사용한 다음 결과 예외를 처리하거나 호출자에게 전파되도록하십시오.


일반적으로 오류가 훨씬 나중에 발생하지 않을 때 조건을 확인하여 오류를 발생시키는 것이 유용합니다. 특히 'user-land'와 'api'코드 사이의 경계에 해당됩니다.

You wouldn't place a metal detector at a police station on the exit door, you would place it at the entrance! If not checking a condition means an error might occur that could have been caught 100 lines earlier, or in a super-class instead of being raised in the subclass then I say there is nothing wrong with checking.

Checking for proper types also makes sense when you are accepting more than one type. It's better to raise an exception that says "I require a subclass of basestring, OR file" than just raising an exception because some variable doesn't have a 'seek' method...

This doesn't mean you go crazy and do this everywhere, for the most part I agree with the concept of exceptions raising themselves, but if you can make your API drastically clear, or avoid unnecessary code execution because a simple condition has not been met do so!


You can try and call the method then catch the exception:

try:
    fp.read()
except AttributeError:
    raise something

If you only want a read and a write method you could do this:

if not (hasattr(fp, 'read') and hasattr(fp, 'write')):
   raise something

If I were you I would go with the try/except method.


Under most circumstances, the best way to handle this is not to. If a method takes a file-like object, and it turns out the object it's passed isn't, the exception that gets raised when the method tries to use the object is not any less informative than any exception you might have raised explicitly.

There's at least one case where you might want to do this kind of check, though, and that's when the object's not being immediately used by what you've passed it to, e.g. if it's being set in a class's constructor. In that case, I would think that the principle of EAFP is trumped by the principle of "fail fast." I'd check the object to make sure it implemented the methods that my class needs (and that they're methods), e.g.:

class C():
    def __init__(self, file):
        if type(getattr(file, 'read')) != type(self.__init__):
            raise AttributeError
        self.file = file

I ended up running into your question when I was writing an open-like function that could accept a file name, file descriptor or pre-opened file-like object.

Rather than testing for a read method, as the other answers suggest, I ended up checking if the object can be opened. If it can, it's a string or descriptor, and I have a valid file-like object in hand from the result. If open raises a TypeError, then the object is already a file.

참고URL : https://stackoverflow.com/questions/1661262/check-if-object-is-file-like-in-python

반응형