2011-12-20 2 views
9

필요한 파일 처리 기능을 포함하는 클래스가 있습니다. 다른 클래스는 filehandler의 인스턴스를 만들고이를 불확실한 시간 동안 사용합니다. 결국 caller이 파괴되어 filehandler에 대한 유일한 참조가 파괴됩니다.파일 주위의 클래스 래퍼 - 더 이상 참조되지 않을 때 파일 핸들을 닫는 적절한 방법

filehandler 파일을 닫는 가장 좋은 방법은 무엇입니까?

나는 현재 __del__(self) 사용하지만 differentquestionsand articlesseveral을보고 난 후에, 나는 이것이 나쁜 일이 간주됩니다 인상입니다.

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __del__(self): 
     self.thefile.close() 

그게 핸들러의 관련 비트입니다. 클래스의 요점은 기본 파일 객체 작업에 대한 세부 사항을 추상화하고 파일 전체를 불필요하게 메모리로 읽지 않도록하는 것입니다. 그러나 기본 파일을 처리하는 부분은 객체가 범위를 벗어날 때 객체를 닫는 것입니다.

callerfilehandler에 관련된 세부 사항을 알거나 신경 쓰지 않아야합니다. 범위를 벗어난 경우 필요한 자원을 해제하는 것은 filehandler 님의 작업입니다. 이것이 처음에 추상화 된 이유 중 하나입니다. 그래서 나는 filehandler 코드를 호출 객체로 옮기거나 새는 추상화를 처리하는 것으로 보입니다.

생각하십니까?

답변

11

__del__은 그 자체로 나쁜 것이 아닙니다. __del__이 정의 된 객체에서 참조주기를 만들지 않도록 조심해야합니다. 사이클을 생성해야하는 경우 (부모는 하위를 부모를 가리킴), weakref 모듈을 사용하고자 할 것입니다.

따라서 __del__은 괜찮습니다. 단지 참고 문헌에주의하십시오.

가비지 수집 : 여기서 중요한 점은 객체가 범위를 벗어나면,이 가비지 수집 할 수 있다는 것입니다, 사실, 그것은 쓰레기 수집 것입니다 ...하지만 때? 언제, 그리고 다른 Python 구현이이 영역에서 다른 특성을 갖는지에 대한 보장은 없습니다. 따라서 리소스를 관리하려면 명시 적으로 .close()filehandler에 추가하거나 사용이 적합한 경우 __enter____exit__ 개의 메소드를 추가하는 것이 좋습니다.

여기에 __enter__ and __exit__ methods에 대해 설명합니다. 그들에 대한 정말 좋은 점은 예외가 발생할 때도 __exit__이 호출되므로 리소스를 셀 수 있거나 리소스를 정상적으로 종료 할 수 있다는 것입니다. __enter__/__exit__에 대한 향상된

귀하의 코드 : 파일이 __enter__ 대신 __init__에 오픈되고 있음을

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefilename = dbf 
    def __enter__(self): 
     self.thefile = open(self.thefilename, 'rb') 
     return self 
    def __exit__(self, *args): 
     self.thefile.close() 

주 - 이것은 당신이 한번의 FileHandler 개체를 만들 수 있습니다, 그리고 때마다 사용 그것을 다시없이 with의 필요 :

fh = filehandler('some_dbf') 
with fh: 
    #file is now opened 
    #do some stuff 
#file is now closed 
#blah blah 
#need the file again, so 
with fh: 
    # file is open again, do some stuff with it 
#etc, etc 
+0

()'__enter의 __'에서 파일을 여는 멋진 트릭 - 당신은 또한 파일의 위치를 ​​유지하기 위해 거기에 몇 가지 마술을 할 수 개폐 사이. – kindall

+1

아주 좋아, 이것은 내가 원한 것에 훨씬 가깝다. ref주기가 내가 확인한 첫 번째 것이고, 나는 아무 것도 가지고 있지 않습니다. 그러나 일부 기사에서는 리프주기에 관계없이 리프 객체에 del 메소드가 있으면 전체 객체 체인을 콜백 할 수 없다고 말합니다. –

+0

@SpencerRathbun : 내가 찾을 수 있었던 모든 문서는 ref 사이클이있는 경우에만 항목을 수집 할 수 없다고 말합니다. ** –

6

클래스를 작성해도 클래스가 파일을 더 이상 안정적으로 닫지는 않습니다. 파일 핸들러 인스턴스를 바닥에 놓기 만하면 파일이 파괴 될 때까지 파일이 닫히지 않습니다. 개체가 가비지 수집 될 때까지 즉시 또는 않을 수도 있지만 바닥에 일반 파일 개체를 놓는 것만 큼 빨리 닫을 수 있습니다. thefile에 대한 유일한 참조가 클래스 객체 내부에있는 경우 filehandler이 가비지 수집 될 때 thefile은 가비지 수집되므로 동시에 닫힙니다.

with open(dbf, 'rb') as thefile: 
    do_something_with(thefile) 

thefile은 항상 할 때마다 with 절 종료 폐쇄되는 것을 보장합니다 :

파일을 사용하는 올바른 방법은 with 문을 사용하는 것입니다. 다른 객체의 내부 파일을 포장 할 경우에 당신은 너무 __enter____exit__ 방법을 정의하여 해당 작업을 수행 할 수 있습니다

class FileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __enter__(self): 
     return self 
    def __exit__(self): 
     self.thefile.close() 

을 다음을 수행 할 수 있습니다 :

with FileHandler(dbf) as fh: 
    do_something_with(fh) 

및 파일이 즉시 종료됩니다 확인 .